doc/api/oauth2.md
{{< details >}}
{{< /details >}}
Use this API to allow third-party services to access GitLab resources for a user with the OAuth 2.0 protocol. For more information, see Configure GitLab as an OAuth 2.0 authentication identity provider.
This functionality is based on the doorkeeper Ruby gem.
{{< history >}}
{{< /history >}}
Many /oauth endpoints support cross-origin resource sharing (CORS). From GitLab 15.1, the following endpoints also
support CORS preflight requests:
/oauth/revoke/oauth/token/oauth/userinfoOnly certain headers can be used for preflight requests:
Authorization header.For example, the X-Requested-With header can't be used for preflight requests.
GitLab supports the following authorization flows:
The draft specification for OAuth 2.1 specifically omits both the Implicit grant and Resource Owner Password Credentials flows.
Refer to the OAuth RFC to find out how all those flows work and pick the right one for your use case.
Authorization code (with or without PKCE) flow requires application to be
registered first via the /user_settings/applications page in your user's account.
During registration, by enabling proper scopes, you can limit the range of
resources which the application can access. Upon creation, you obtain the
application credentials: Application ID and Client Secret. The Client Secret
must be kept secure. It is also advantageous to keep the Application ID
secret when your application architecture allows.
For a list of scopes in GitLab, see the provider documentation.
To protect redirect-based flows,
the OAuth specification recommends the use of "One-time use CSRF tokens carried in the state
parameter, which are securely bound to the user agent", with each request to the
/oauth/authorize endpoint. This can prevent
CSRF attacks.
For production, use HTTPS for your redirect_uri.
For development, GitLab allows insecure HTTP redirect URIs.
As OAuth 2.0 bases its security entirely on the transport layer, you should not use unprotected URIs. For more information, see the OAuth 2.0 RFC and the OAuth 2.0 Threat Model RFC.
In the following sections you can find detailed instructions on how to obtain authorization with each flow.
{{< history >}}
ff_oauth_redirect_to_sso_login. Disabled by default.ff_oauth_redirect_to_sso_login removed.{{< /history >}}
The PKCE RFC includes a detailed flow description, from authorization request through access token. The following steps describe our implementation of the flow.
The Authorization code with PKCE flow, PKCE for short, makes it possible to securely perform the OAuth exchange of client credentials for access tokens on public clients without requiring access to the Client Secret at all. This makes the PKCE flow advantageous for single page JavaScript applications or other client side apps where keeping secrets from the user is a technical impossibility.
Before starting the flow, generate the STATE, the CODE_VERIFIER and the CODE_CHALLENGE.
STATE a value that can't be predicted used by the client to maintain
state between the request and callback. It should also be used as a CSRF token.CODE_VERIFIER is a random string, between 43 and 128 characters in length,
which use the characters A-Z, a-z, 0-9, -, ., _, and ~.CODE_CHALLENGE is a URL-safe base64-encoded string of the SHA256 hash of the
CODE_VERIFIER:
Base64.urlsafe_encode64(Digest::SHA256.digest(CODE_VERIFIER), padding: false).CODE_VERIFIER string of ks02i3jdikdo2k0dkfodf3m39rjfjsdk0wk349rj3jrhf when hashed
and encoded using the previous Ruby snippet produces a CODE_CHALLENGE string
of 2i0WFA-0AerkjQm4X4oDEhqA17QIAKNjXpagHBXmO_U.Request authorization code. To do that, you should redirect the user to the
/oauth/authorize page with the following query parameters:
https://gitlab.example.com/oauth/authorize?client_id=APP_ID&redirect_uri=REDIRECT_URI&response_type=code&state=STATE&scope=REQUESTED_SCOPES&code_challenge=CODE_CHALLENGE&code_challenge_method=S256&root_namespace_id=ROOT_NAMESPACE_ID
This page asks the user to approve the request from the app to access their
account based on the scopes specified in REQUESTED_SCOPES. The user is then
redirected back to the specified REDIRECT_URI. The scope parameter
is a space-separated list of scopes associated with the user.
For example,scope=read_user+profile requests the read_user and profile scopes.
The root_namespace_id is the root namespace ID associated with the project. This optional parameter
should be used when SAML SSO is configured for the associated group.
The redirect includes the authorization code, for example:
https://example.com/oauth/redirect?code=1234567890&state=STATE
With the authorization code returned from the previous request (denoted as
RETURNED_CODE in the following example), you can request an access_token, with
any HTTP client. The following example uses Ruby's rest-client:
parameters = 'client_id=APP_ID&code=RETURNED_CODE&grant_type=authorization_code&redirect_uri=REDIRECT_URI&code_verifier=CODE_VERIFIER'
RestClient.post 'https://gitlab.example.com/oauth/token', parameters
Example response:
{
"access_token": "de6780bc506a0446309bd9362820ba8aed28aa506c71eedbe1c5c4f9dd350e54",
"token_type": "bearer",
"expires_in": 7200,
"refresh_token": "8257e65c97202ed1726cf9571600918f3bffb2544b26e00a61df9897668c33a1",
"created_at": 1607635748
}
To retrieve a new access_token, use the refresh_token parameter. Refresh tokens may
be used even after the access_token itself expires. This request:
access_token and refresh_token. parameters = 'client_id=APP_ID&refresh_token=REFRESH_TOKEN&grant_type=refresh_token&redirect_uri=REDIRECT_URI'
RestClient.post 'https://gitlab.example.com/oauth/token', parameters
Example response:
{
"access_token": "c97d1fe52119f38c7f67f0a14db68d60caa35ddc86fd12401718b649dcfa9c68",
"token_type": "bearer",
"expires_in": 7200,
"refresh_token": "803c1fd487fec35562c205dac93e9d8e08f9d3652a24079d704df3039df1158f",
"created_at": 1628711391
}
[!note] The
redirect_urimust match theredirect_uriused in the original authorization request.
You can now make requests to the API with the access token.
{{< history >}}
ff_oauth_redirect_to_sso_login. Disabled by default.ff_oauth_redirect_to_sso_login removed.{{< /history >}}
[!note] Check the RFC spec for a detailed flow description.
The authorization code flow is essentially the same as authorization code flow with PKCE,
Before starting the flow, generate the STATE. It is a value that can't be predicted
used by the client to maintain state between the request and callback. It should also
be used as a CSRF token.
Request authorization code. To do that, you should redirect the user to the
/oauth/authorize page with the following query parameters:
https://gitlab.example.com/oauth/authorize?client_id=APP_ID&redirect_uri=REDIRECT_URI&response_type=code&state=STATE&scope=REQUESTED_SCOPES&root_namespace_id=ROOT_NAMESPACE_ID
This page asks the user to approve the request from the app to access their
account based on the scopes specified in REQUESTED_SCOPES. The user is then
redirected back to the specified REDIRECT_URI. The scope parameter
is a space-separated list of scopes associated with the user.
For example,scope=read_user+profile requests the read_user and profile scopes.
The root_namespace_id is the root namespace ID associated with the project. This optional parameter
should be used when SAML SSO is configured for the associated group.
The redirect includes the authorization code, for example:
https://example.com/oauth/redirect?code=1234567890&state=STATE
With the authorization code returned from the previous request (shown as
RETURNED_CODE in the following example), you can request an access_token, with
any HTTP client. The following example uses Ruby's rest-client:
parameters = 'client_id=APP_ID&client_secret=APP_SECRET&code=RETURNED_CODE&grant_type=authorization_code&redirect_uri=REDIRECT_URI'
RestClient.post 'https://gitlab.example.com/oauth/token', parameters
Example response:
{
"access_token": "de6780bc506a0446309bd9362820ba8aed28aa506c71eedbe1c5c4f9dd350e54",
"token_type": "bearer",
"expires_in": 7200,
"refresh_token": "8257e65c97202ed1726cf9571600918f3bffb2544b26e00a61df9897668c33a1",
"created_at": 1607635748
}
To retrieve a new access_token, use the refresh_token parameter. Refresh tokens may
be used even after the access_token itself expires. This request:
access_token and refresh_token. parameters = 'client_id=APP_ID&client_secret=APP_SECRET&refresh_token=REFRESH_TOKEN&grant_type=refresh_token&redirect_uri=REDIRECT_URI'
RestClient.post 'https://gitlab.example.com/oauth/token', parameters
Example response:
{
"access_token": "c97d1fe52119f38c7f67f0a14db68d60caa35ddc86fd12401718b649dcfa9c68",
"token_type": "bearer",
"expires_in": 7200,
"refresh_token": "803c1fd487fec35562c205dac93e9d8e08f9d3652a24079d704df3039df1158f",
"created_at": 1628711391
}
[!note] The
redirect_urimust match theredirect_uriused in the original authorization request.
You can now make requests to the API with the access token returned.
{{< history >}}
oauth2_device_grant_flow.oauth2_device_grant_flow removed.{{< /history >}}
[!note] Check the RFC spec for a detailed description of the device authorization grant flow, from device authorization request to token response from the browser login.
The device authorization grant flow makes it possible to securely authenticate your GitLab identity from input constrained devices where browser interactions are not an option.
This makes the device authorization grant flow ideal for users attempting to use GitLab services from headless servers or other devices with no, or limited, UI.
To request device authorization, a request is sent from the input-limited
device client to https://gitlab.example.com/oauth/authorize_device. For example:
parameters = 'client_id=UID&scope=read'
RestClient.post 'https://gitlab.example.com/oauth/authorize_device', parameters
After a successful request, a response containing a verification_uri is returned to the user. For example:
{
"device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS",
"user_code": "0A44L90H",
"verification_uri": "https://gitlab.example.com/oauth/device",
"verification_uri_complete": "https://gitlab.example.com/oauth/device?user_code=0A44L90H",
"expires_in": 300,
"interval": 5
}
The device client displays the user_code and verification_uri from the response to the
requesting user. That user then, on a secondary device with browser access:
Immediately after displaying the verification_uri and user_code, the device client
begins polling the token endpoint with the associated device_code returned in the initial response:
parameters = 'grant_type=urn:ietf:params:oauth:grant-type:device_code
&device_code=GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS
&client_id=1406020730'
RestClient.post 'https://gitlab.example.com/oauth/token', parameters
The device client receives a response from the token endpoint. If the authorization was successful, a success response is returned, otherwise, an error response is returned. Potential error responses are categorized by either of the following:
Those error responses specific to the device flow are described in the following content. For more information on each potential response, see the relevant RFC spec for device authorization grant and the RFC spec for authorization tokens.
Example response:
{
"error": "authorization_pending",
"error_description": "..."
}
On receipt of this response, the device client continues polling.
If the polling interval is too short, a slow down error response is returned. For example:
{
"error": "slow_down",
"error_description": "..."
}
On receipt of this response, the device client reduces its polling rate and continues polling at the new rate.
If the device code expires before authentication is complete, an expired token error response is returned. For example:
{
"error": "expired_token",
"error_description": "..."
}
At that point, the device-client should stop and initiate a new device authorization request.
If the authorization request was denied, an access denied error response is returned. For example:
{
"error": "access_denied",
"error_description": "..."
}
The authentication request has been rejected. The user should verify their credentials or contact their system administrator
After the user successfully authenticates, a success response is returned:
{
"access_token": "TOKEN",
"token_type": "Bearer",
"expires_in": 7200,
"scope": "read",
"created_at": 1593096829
}
At this point, the device authentication flow is complete. The returned access_token can be provided to GitLab to authenticate the user identity when accessing GitLab resources, such as when cloning over HTTPS or accessing the API.
A sample application that implements the client side device flow can be found at: https://gitlab.com/johnwparent/git-auth-over-https.
[!note] Check the RFC spec for a detailed flow description.
Resource owner password credentials are disabled for users with two-factor authentication turned on and enterprise users with password authentication disabled for their group. These users can access the API using personal access tokens instead.
Ensure the Allow password authentication for Git over HTTP(S) checkbox is selected for the GitLab instance to support the password credentials flow.
In this flow, a token is requested in exchange for the resource owner credentials (username and password).
The credentials should only be used when:
[!warning] Never store the user's credentials and only use this grant type when your client is deployed to a trusted environment, in 99% of cases personal access tokens are a better choice.
Even though this grant type requires direct client access to the resource owner credentials, the resource owner credentials are used for a single request and are exchanged for an access token. This grant type can eliminate the need for the client to store the resource owner credentials for future use, by exchanging the credentials with a long-lived access token or refresh token.
To request an access token, you must make a POST request to /oauth/token with
the following parameters:
{
"grant_type" : "password",
"username" : "[email protected]",
"password" : "secret"
}
Example cURL request:
echo 'grant_type=password&username=<your_username>&password=<your_password>' > auth.txt
curl --request POST \
--url "https://gitlab.example.com/oauth/token" \
--data "@auth.txt"
You can also use this grant flow with registered OAuth applications, by using
HTTP Basic Authentication with the application's client_id and client_secret:
echo 'grant_type=password&username=<your_username>&password=<your_password>' > auth.txt
curl --request POST \
--url "https://gitlab.example.com/oauth/token" \
--data "@auth.txt" \
--user client_id:client_secret
Then, you receive a response containing the access token:
{
"access_token": "1f0af717251950dbd4d73154fdf0a474a5c5119adad999683f5b450c460726aa",
"token_type": "bearer",
"expires_in": 7200
}
By default, the scope of the access token is api, which provides complete read/write access.
For testing, you can use the oauth2 Ruby gem:
client = OAuth2::Client.new('the_client_id', 'the_client_secret', :site => "https://example.com")
access_token = client.password.get_token('[email protected]', 'secret')
puts access_token.token
access tokenThe access token allows you to make requests to the API on behalf of a user.
You can pass the token either as GET parameter:
GET https://gitlab.example.com/api/v4/user?access_token=OAUTH-TOKEN
or you can put the token to the Authorization header:
curl --header "Authorization: Bearer OAUTH-TOKEN" "https://gitlab.example.com/api/v4/user"
access tokenA token with scope
read_repository or write_repository can access Git over HTTPS. Use the token as the password.
You can set the username to any string value. You should use oauth2:
https://oauth2:<your_access_token>@gitlab.example.com/project_path/project_name.git
Alternatively, you can use a Git credential helper to authenticate to GitLab with OAuth. This handles OAuth token refresh automatically.
To verify the details of a token, use the token/info endpoint provided by the
Doorkeeper gem. For more information, see
/oauth/token/info.
You must supply the access token, either:
As a parameter:
GET https://gitlab.example.com/oauth/token/info?access_token=<OAUTH-TOKEN>
In the Authorization header:
curl --header "Authorization: Bearer <OAUTH-TOKEN>" "https://gitlab.example.com/oauth/token/info"
The following is an example response:
{
"resource_owner_id": 1,
"scope": ["api"],
"expires_in": null,
"application": {"uid": "1cb242f495280beb4291e64bee2a17f330902e499882fe8e1e2aa875519cab33"},
"created_at": 1575890427
}
The fields scopes and expires_in_seconds are included in the response but are now deprecated. The scopes field is an alias for scope, and the expires_in_seconds field is an alias for expires_in. For more information, see Doorkeeper API changes.
To revoke a token, use the revoke endpoint. The API returns a 200 response code and an empty
JSON hash to indicate success.
parameters = 'client_id=APP_ID&client_secret=APP_SECRET&token=TOKEN'
RestClient.post 'https://gitlab.example.com/oauth/revoke', parameters
Standard OAuth 2.0 tokens support different degrees of access to GitLab registries, as they: