Authentication
Sessions
All authenticated endpoints require a valid session to access. Information on how to obtain and use a session can be found here.
Sessions last 12 hours until they are considered expired and have to be renewed.
Authentication Preferences
Company Admins and Owners can control which authentication methods are enabled for their users via our Authentication Preferences settings under the Security tab. Here you can enable or disable each of our authentication methods, Password, Google, OAuth and SAML. Additionally you can enable or disable some of the extra controls like requiring MFA during password login, or requiring a claim be present during SAML logins.
MFA
Users can enable a multi factor authentication for password based logins in Gremlin Company Settings under the Security tab. Currently, Time-based Token (Time-based One Time Passwords, TOTP) MFA is supported. An example of a compatible authenticator is the Google Authenticator, available on the Apple App Store and Google Play.
MFA can be forced for users across the entire company. When MFA Required
is enabled via the Authentication Preferences, all users who authenticate without MFA will be provided with a secret key and QR barcode to setup their authenticator. Certain user roles also have the ability to disable MFA for individual users within their company, useful in cases where a user loses their authenticator.
When logging in with SSO, you will not be prompted to use MFA; even if it is enabled for your account. We defer to the SSO provider to enforce MFA.
SAML
Companies who host their own SAML compatible Identity Provider (IDP) can utilize SAML sign-on for their users to authenticate with Gremlin. SAML provides your organization complete control over the users authentication process and experience. When using SAML, authentication requests are forwarded to your IDP, which performs authentication as your company specifies. Once a user has authenticated, their details such as their email address, are securely delivered to Gremlin and the user is granted access.
SAML configuration can be performed by users with the correct roles in Gremlin Settings on the Security tab.
In order to configure your IDP for SAML please use our Service Provider (SP) metadata, available with the following command:
1curl https://api.gremlin.com/v1/users/auth/saml/metadata
Important SAML fields
Assertion Consumer Service URL -
https://api.gremlin.com/v1/users/auth/saml/acs
: Represents the location your IDP will send the SAML assertion to be validated by our SP.Service Provider Entity ID -
http://api.gremlin.com/saml
: Unique identifier for the Gremlin SP.- This is different from the Entity ID you'll need to enter in your SAML configuration page at
/settings/security
. The Entity ID there is your IDP Entity ID, which is unique to your IDP. This value is Gremlin's unique SP Entity ID, which you may be required to provide to your IDP when setting up IDP initiated logins.
- This is different from the Entity ID you'll need to enter in your SAML configuration page at
RelayState -
<Company Name>|||https://app.gremlin.com/users/sso/saml/acs|||/
: Three parameters seperated by|||
. The first being your company name. The second parameter is the app address, where our ACS sends the user once it is done validating. The last is where we send the user once the login is fully complete, the default destination is the home page.NameID Format -
urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
: Specifies the format of the NameID within the SAML assertion. We require a valid email be used.Signature Method -
http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
: What we use for signing our SAML metadata and requests.Bindings:
- AuthnRequest -
urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect
: Used by our SP to send users to their IDP during SP initiated logins. - AuthnResponse -
urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST
: Used by your IDP when returning the response to our ACS.
- AuthnRequest -
SAML claims
Gremlin supports SAML claims, allowing you to send information during the SAML authentication process about what roles and team memberships a user should possess. Using the information provided in the claim, the user will either be updated if they already exist, or created if they do not yet exist. These claims take the form of an AttributeStatement
which is included within the Assertion
block that is sent in the SAML Response from your IDP. Within this AttributeStatement
are Attributes
defining company level roles and team memberships for the user.
Company roles attribute (required)
Named: company:roles
. This can have multiple AttributeValues
, each containing a valid role. A list of these valid roles can be found here. Here is an example:
1<saml:Attribute Name="company:roles" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">2 <saml:AttributeValue xsi:type="xs:string">COMPANY_OWNER</saml:AttributeValue>3 <saml:AttributeValue xsi:type="xs:string">COMPANY_USER</saml:AttributeValue>4</saml:Attribute>
Only one company roles attribute may be present in the claim.
Team membership attribute (optional)
There are two different ways to define the team membership attribute depending on your IDP limitations. Only one format may be present in a claim.
Team roles format
You define a singular Attribute
named team:roles
. The AttributeValues
of this Attribute
define the team the user is a member of and the roles they hold. The format for these AttributeValues
is teamName;Role,Role ...
or teamId;Role,Role ...
where teamName
and teamId
is the name/identifier for the team you want the user to be a member of.
The name and identifier can be found by going to the team's configuration page:
Here is example of what an Attribute
in this format would look like containing two team memberships. One AttributeValue
uses the teamName;Role,Role
format and the other uses the teamId;Role,Role
format, both are valid in this situation.
1<saml:Attribute Name="team:roles" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">2 <saml:AttributeValue xsi:type="xs:string">My Other Team;TEAM_MANAGER,TEAM_USER</saml:AttributeValue>3 <saml:AttributeValue xsi:type="xs:string">6b336d49-e8ce-5a73-976c-39000cf3d1d0;TEAM_USER</saml:AttributeValue>4</saml:Attribute>
Team memberships format
You define an Attribute
per team membership for the user. Each Attribute
name is in the format team:teamId
or team:teamName
. The roles the user possesses for this team are defined in the AttributeValues
of this Attribute
. Each AttributeValue
can contain a singular role, e.g. TEAM_USER
, or it can contain a comma-separated list of roles, e.g. TEAM_USER,TEAM_MANAGER
.
Here is an example of two team memberships in the form of multiple Attributes
. One uses the team:teamId
attribute name with one role per AttributeValue
and the other uses the team:teamName
attribute name with one AttributeValue
containing a comma-separated list of roles, both are valid in this situation.
1<saml:Attribute Name="team:6b336d49-e8ce-5a73-976c-39000cf3d1d0" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">2 <saml:AttributeValue xsi:type="xs:string">TEAM_MANAGER</saml:AttributeValue>3 <saml:AttributeValue xsi:type="xs:string">TEAM_USER</saml:AttributeValue>4</saml:Attribute>5<saml:Attribute Name="team:My Other Team" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">6 <saml:AttributeValue xsi:type="xs:string">TEAM_USER,TEAM_MANAGER</saml:AttributeValue>7</saml:Attribute>
These will overwrite any existing roles and team memberships that the user has. If the user currently has the COMPANY_OWNER
role, and the claim only specifies COMPANY_USER
, then the user will now have COMPANY_USER
as their only role. The same applies for team memberships, if a user belongs to teamA
and teamB
, yet the claim only has an attribute specifying membership and role information for teamA
, then the user will no longer be a member of teamB
. If a claim is sent with no team memberships, then the user will be removed from any teams they are currently on.
Gremlin Okta integration
If you are using Okta as your IDP, you can utilize Gremlin's Okta Integration in Okta's Integration Network. Instructions on how to setup our integration can be found in Okta's SAML documentaion.
ADFS SAML setup example
Prerequisites
- An Active Directory (AD) instance where users have a specified email address.
- A running Microsoft Server with ADFS deployed.
- An SSL certificate to secure your ADFS endpoints.
Add a relying party trust
- Save the Service Provider (SP) metadata as a file. SP metadata is available from the metadata endpoint.
- Open the ADFS management console and select
AD FS > Relying Party Trusts
. Right click Relying Party Trusts and selectAdd Relying Party Trust
. - In the Welcome screen select the desired option for
Claims aware
orNon claims aware
. We have selected Claims aware. - In the Select Data Source screen, choose
Import data about the relying party from a file
. Enter the path to the file downloaded in step 1. Note: It is possible to enter this information manually, or ask ADFS to retrieve it directly. See ADFS documentation for more information. - On the Specify Display Name screen enter the desired
Display Name
for this service as well as anyNotes
. You can enter anything you wish here. - In the Choose Access Control Policy screen select the access control policy suitable for your environment. We have chosen to
Permit everyone and require MFA
. - In the Ready to Add Trust screen, you can review the configuration and make any necessary changes. For more information about a particular configuration setting please consult the ADFS documentation.
- In the Finish screen you can select
Configure claims issuance policy for this application
if desired. Click Close.
Okta setup example
Please see the Okta SAML documentation for an example of how to integrate Gremlin and Okta.
OAuth
Gremlin supports OAuth authentication via custom defined OAuth providers.
Configuring an OAuth provider
When configuring an OAuth provider we require the following information:
Authoriztion URI
: Used to authenticate against the OAuth provider. We will redirect the user to this URL when they initate a OAuth login.Token URI
: Used to exchange an OAuth code, obtained after logging into the OAuth provider, for an access token.User Info URI
: Used to query for the email of the user..Client Id
: The public identifier obtained when registering Gremlin with your OAuth provider.Client Secret
: The secret obtained when registering Gremlin with your OAuth provider.Scope (optional)
: Define what level of access the access token will have that Gremlin obtains during the OAuth login. The default isemail
. If you change it from the default, the scope provided must be able to read the email of the user.
To configure these settings you can send the following POST
request to our API:
1curl -X POST \2 --header "Content-Type: application/json" \3 --header "Authorization: $bearertoken" \4 https://api.gremlin.com/v1/companies/$companyId/oauth/settings \5 --data '6 {7 "authorizationUri": "https://example.com/oauth/authorize",8 "tokenUri": "https://example.com/oauth/token",9 "userInfoUri": "https://example.com/user",10 "clientId": "exampleClientId",11 "clientSecret": "exampleClientSecret",12 "scope": "email"13 }'
Authenticating via OAuth
After configuring your OAuth provider, you are ready to intiate a OAuth login flow.
To illustrate the flow we have provided a commented python script that explains each step of the process. The requests
library is a prerequisite for running this script as well as Python 3.
1import requests23COMPANY_NAME = 'Example Company'45"""6Initiates OAuth login with Gremlin7We set `allow_redirects=false` here so we can capture8the response and extract the state cookie9"""10login_response = requests.get(11 f"https://api.gremlin.com/v1/oauth/login?companyName={COMPANY_NAME}",12 allow_redirects=False13)14assert login_response.status_code == 3071516"""17Response is a 307 redirect to your OAuth provider with the URL18in the Location header as well as the OAuth state cookie.19This cookie is required to prevent against CSRF attacks,20additionally it tracks your state as the OAuth flow progresses.21You need to extract this cookie so it can be used later22when being redirected back to the Gremlin API.23"""24state_cookie = login_response.cookies['oauth_state']25oauth_provider_login_url = login_response.headers['Location']2627assert state_cookie != None28assert oauth_provider_login_url != None2930"""31This part is implementation specific depending on your OAuth provider.32Different OAuth providers may require different things when authenticating the user.33Also for the first time you authenticate to your OAuth provider with Gremlin,34a browser may be required so that you can grant35Gremlin access based on the scope we request.3637This example is performing a simple POST request to an38example OAuth provider with the following information:3940 - email: Login email for your user41 - password: Login password for your user42 - state: Value of the state cookie obtained in the previous step43 - redirectUri: URL where your provider should redirect you to after authenticating.44 It should be https://api.gremlin.com/v1/oauth/callback45 - clientId: Client Id obtained when registering Gremlin with your OAuth provider4647The login specific information may vary depending on your OAuth provider,48but the state, redirectUri and clientId paramaters49are often required across all types of provider.50"""51body = {52 'email': 'test@example.com',53 'password': '*********',54 'state': state_cookie, # obtained in earlier step55 'redirectUri': 'https://api.gremlin.com/v1/oauth/callback',56 'clientId': 'exampleClientId'57}5859"""60Don't follow redirect as we need to add the state cookie to the next request61"""62oauth_provider_login_response = requests.post(63 oauth_provider_login_url,64 data=body,65 allow_redirects=False66)6768"""69You have now successfully authenticted with your OAuth provider,70now continue the flow by following the redirect your OAuth provider71created back to Gremlins /oauth/callback endpoint72"""73gremlin_callback_url = oauth_provider_login_response.headers['Location']74assert gremlin_callback_url != None7576"""77Add the state cookie to the request and then follow the redirect78to Gremlins /oauth/callback endpoint. If the state cookie is not79added the request will fail. There is a state parameter in the80redirect URL you are following and it needs to match the81value in the cookie. This helps prevent CSRF attacks.82"""83cookie = {84 'oauth_state': state_cookie85}86gremlin_callback_response = requests.get(87 gremlin_callback_url,88 cookies=cookie89)9091"""92The response from the callback endpoint will contain the `access_token` in JSON93This is the end of the OAuth specific flow. This `access_token` can94now be exchanged for a Gremlin session.95"""96assert gremlin_callback_response.status_code == 2009798access_token = gremlin_callback_response.json()['access_token']99assert access_token != None100101"""102We now need a valid Gremlin session which can be used to access103the authenticated portions of our API. Craft a request to /users/auth/sso104to exchange access_token for a Gremlin session105"""106body = {107 'companyName': COMPANY_NAME,108 'accessToken': access_token,109 'provider': 'oauth',110}111sso_response = requests.post(112 f"https://api.gremlin.com/v1/users/auth/sso?getCompanySession=true",113 data=body114)115assert sso_response.status_code == 200116117"""118The response is a JSON representation of the session.119In this JSON response is the `header` field which contains a120Bearer token that can be used in the `Authorization` header121when making requests to the Gremlin API.122"""123bearer_token = sso_response.json()['header']124assert bearer_token != None125126"""127Done!128"""
If you encounter any errors during this process or have any questions please reach out to support@gremlin.com.
OpenID Connect Claims
Gremlin supports the OpenID Connect extension to OAuth, allowing you to specify roles and team memberships for your user through the form of JSON Web Token claims.
The first claim we require is either the sub
or email
claim. We look at both when determining the email for the user being authenticated. At least one of these claims must be present and contain a valid email. The sub
claim will take priority over the email
claim if both are found to be valid emails.
Specifying the role and team memberships for the user are supported via the following two custom claims:
company_roles
: A list of strings, each value is a role that the user will hold at the company level.team_roles
: A list of strings, each value represents a single team membership the user will have. The team membership is defined in the following format -teamName;Role1,Role2
.
Here is an example of what this would look like in the JSON Web Token:
1{2 "company_roles": [3 "COMPANY_USER"4 ],5 "team_roles": [6 "Team A;TEAM_USER",7 "Team B;TEAM_MANAGER,TEAM_USER"8 ]9}
In the above example, the user will be given the Company User
role, and will have a membership in Team A with the Team User
role and a membership in Team B with the Team User
and Team Manager
roles.