Bitbucket OAuth 2.0 provider API

On this page

Still need help?

The Atlassian Community is here for you.

Ask the community

Bitbucket (Data Center and Server) provides APIs to allow external services to access resources on a user’s behalf with the OAuth 2.0 protocol.

If you already have an integration that you’d like to add to Bitbucket, see Configure an incoming link for detailed steps. If not, this page will help you understand the details of our OAuth 2.0 implementation so you can create such an integration.

Supported OAuth 2.0 flows

We support the following OAuth 2.0 flows:

We don’t support Implicit Grant and Resource Owner Password Credentials flows, as they will be deprecated in the next OAuth specification version.

For more information on how these flows work, see OAuth RFC. This should help you understand the flows and choose the right one for you.

Security recommendations

Here are some recommendations on how to improve security:

Preventing CSRF attacks

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” using the state query parameter, with each request to the /rest/oauth2/latest/authorize endpoint. This can prevent CSRF attacks.

Using HTTPS in production

For production environments, use HTTPS for the redirect uri. This is important, as OAuth 2.0 bases its security on the transport layer. For more info, see the OAuth 2.0 RFC and the OAuth 2.0 Threat Model RFC.

For the same reason, we also enforce HTTPS for the base URL of production environments. You can use insecure URIs and base URLs for staging or development environments by enabling the relevant system properties.

Authorization code with Proof Key for Code Exchange (PKCE)

This flow lets you securely perform the OAuth exchange of client credentials for access tokens on public clients. The following steps and parameters describe our implementation of this flow.

Parameters

Here are parameters you’ll use in this flow:

ParameterDescriptionRequired
redirect_uriURL the user is redirected to after authorizing the request.Yes
client_idClient ID received from Jira after registering your application.Yes
response_time

Authorization code.

Yes
scopeScopes that define application’s permissions to the user account. For more info, see Scopes.Yes
code_challenge
  • For sha256, generate this using the following pseudocode: BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))

  • For plain, this can be the generated code_verifier.

Yes
code_challenge_methodCan be plain or sha256 depending on how the code_challenge was generated.Yes
code_verifierHigh-entropy cryptographic random STRING using the unreserved characters: [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~". It must be between 43-127 characters. For more info, see the RFC.Yes
stateA value that can't be predicted. It will be used by the client to maintain state between the request and callback. It should also be used as a CSRF token. It can be generated in a similar manner to code_verifier.No

Before you begin

  • Register your application in Bitbucket by creating an incoming link in application links. During registration, you can enable proper scopes to limit the range of resources which the application can access. After creating the link, you should receive the OAuth credentials: Client ID and Client secret - keep them secure. For more info, see Configure an incoming link.

  • Before starting the flow, generate the state (optional), code_verifier, code_challenge, and code_challenge_method.

Steps

1. Request authorization code by redirecting the user to the /rest/oauth2/latest/authorize page with the following query parameters:

curl https://atlassian.example.com/rest/oauth2/latest/authorize?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&response_type=code&state=STATE&scope=SCOPE&code_challenge=CODE_CHALLENGE&code_challenge_method=S256

This is the consent screen that asks the user to approve the application’s request to access their account with the scopes specified in scope. The user is then redirected to the URL specified in redirect_uri. The redirect includes the authorization code, like in the following example:

https://atlassian.example.com/plugins/servlet/oauth2/consent?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE&code_challenge_method=CODE_CHALLENGE_METHOD&code_challenge=CODE_CHALLENGE


2. With the authorization code returned from the previous request, you can request an access_token, with any HTTP client. The following example uses curl:

curl -X POST https://atlassian.example.com/rest/oauth2/latest/token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&code=CODE&grant_type=authorization_code&redirect_uri=REDIRECT_URI&code_verifier=CODE_VERIFIER

Example response

{
 "access_token": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjNmMTQ3NTUzYjg3OTQ2Y2FhMWJhYWJkZWQ0MzgwYTM4In0.EDnpBl0hd1BQzIRP--xEvyW1F6gDuiFranQCvi98b2c",
 "token_type": "bearer",
 "expires_in": 7200,
 "refresh_token": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6ImMwZTMxYmZjYTI2NWI0YTkwMzBiOGM2OTJjNWIyMTYwIn0.grHOsso3B3kaSxNd0QJfj1H3ayjRUuA75SiEt0usmiM",
 "created_at": 1607635748
}


3. To retrieve a new access_token, use the refresh_token parameter. Refresh tokens may be used even after the access_token itself expires. The following request:

  • Invalidates the existing access_token and refresh_token.

  • Sends new tokens in the response

curl -X POST https://atlassian.example.com/rest/oauth2/latest/token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&refresh_token=REFRESH_TOKEN&grant_type=refresh_token&redirect_uri=REDIRECT_URI

Example response

{
  "access_token": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6ImJmZjg4MzU5YTVkNGUyZmQ3ZmYwOTEwOGIxNjg4MDA0In0.BocpI91mpUzWskyjxHp57hnyl8ZcHehGJwmaBsGJEMg",
  "token_type": "bearer",
  "expires_in": 7200,
  "refresh_token": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6Ijg1NjQ1YjA1NGJiYmZkNjVmMDNkMzliYzM0YzQ4MzZjIn0.4MSMIG46zjB9QCV-qCCglgojM5dL7_E2kcqmiV46YQ4",
  "created_at": 1628711391
}

You can now make requests to the API with the access token. For more info, see Access Bitbucket API with access token below.

Authorization code

This flow lets you securely perform the OAuth exchange of client credentials for access tokens on public clients.

Parameters

Here are parameters you’ll use in this flow:

ParameterDescriptionRequired
redirect_uriURL the user is redirected to after authorizing the request.Yes
client_idClient ID received from Jira after registering your application.Yes
response_typeAuthorization code.Yes
scopeScopes that define application’s permissions to the user account. For more info, see Scopes.Yes
stateA value that can't be predicted. It will be used by the client to maintain state between the request and callback. It should also be used as a CSRF token.No

Before you begin

  • Register your application in Bitbucket by creating an incoming link in application links. During registration, you can enable proper scopes to limit the range of resources which the application can access. After creating the link, you should receive the OAuth credentials: Client ID and Client secret - keep them secure. For more info, see Configure an incoming link.

  • If you want to use the optional state parameter, generate it before starting the flow.

Steps

1. Request the authorization code by redirecting the user to the /oauth/authorize page with the following query parameters:

curl https://atlassian.example.com/rest/oauth2/latest/authorize?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&response_type=code&state=STATE&scope=SCOPE

This is the consent screen that asks the user to approve the application’s request to access their account with the scopes specified in scope. The user is then redirected to the URL specified in redirect_uri. The redirect includes the authorization code, like in the following example:

https://atlassian.example.com/plugins/servlet/oauth2/consent?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE

2. With the authorization code (response_type) returned from the previous request, you can request an access_token, with any HTTP client. The following example uses Ruby’s rest-client:

curl -X POST https://atlassian.example.com/rest/oauth2/latest/token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&code=CODE&grant_type=authorization_code&redirect_uri=REDIRECT_URI

Example response

{
 "access_token": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjNmMTQ3NTUzYjg3OTQ2Y2FhMWJhYWJkZWQ0MzgwYTM4In0.EDnpBl0hd1BQzIRP--xEvyW1F6gDuiFranQCvi98b2c",
 "token_type": "bearer",
 "expires_in": 7200,
 "refresh_token": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6ImMwZTMxYmZjYTI2NWI0YTkwMzBiOGM2OTJjNWIyMTYwIn0.grHOsso3B3kaSxNd0QJfj1H3ayjRUuA75SiEt0usmiM",
 "created_at": 1607635748
}

3. 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:

  • Invalidates the existing access_token and refresh_token.

  • Sends new tokens in the response.

curl -X POST https://atlassian.example.com/rest/oauth2/latest/token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&refresh_token=REFRESH_TOKEN&grant_type=refresh_token&redirect_uri=REDIRECT_URI

Example response

{
  "access_token": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6ImJmZjg4MzU5YTVkNGUyZmQ3ZmYwOTEwOGIxNjg4MDA0In0.BocpI91mpUzWskyjxHp57hnyl8ZcHehGJwmaBsGJEMg",
  "token_type": "bearer",
  "expires_in": 7200,
  "refresh_token": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6Ijg1NjQ1YjA1NGJiYmZkNjVmMDNkMzliYzM0YzQ4MzZjIn0.4MSMIG46zjB9QCV-qCCglgojM5dL7_E2kcqmiV46YQ4",
  "created_at": 1628711391
}

You can now make requests to the API with the access token returned. For more info, see Access Bitbucket API with access token below.

Access Bitbucket API with access token

The access token allows you to make requests to the API on behalf of a user. You can put the token in the Authorization header:

curl --header "Authorization: Bearer OAUTH2-TOKEN" "https://atlassian.example.com/rest/api/latest/issue/JRA-9"

Scopes

The scope parameter is required in both flows. It allows you to specify the permission scopes your application can request from the authorizing user. Note that regardless of which scopes you choose, the actual permissions will always be capped at what the user can actually do.

Here you can find the scope keys you can use in your requests, as values of the scope parameter:

Scope keyDescription
No scope / PUBLIC_REPOS

View public projects and repositories

View projects and repositories that are publicly accessible, including pulling code and cloning repositories.

ACCOUNT_WRITE

Update user account

Update the user account settings.

REPO_READ

View projects and repositories

View projects and repositories the user account can view, including pulling code, cloning, and forking repositories. Create and comment on pull requests.

REPO_WRITE

Update projects and repositories

Update projects and repositories the user account can change, including pushing code and merging pull requests.

REPO_ADMIN

Administer repositories

Perform administrative functions on repositories and pull requests the user account can change, including deleting pull requests and updating repository settings and permissions.

PROJECT_ADMIN

Administer projects

Perform administrative functions on projects, repositories, and pull requests the user account can change, including creating new repositories and updating project settings and permissions.

ADMIN_WRITE

Administer Bitbucket

Perform most administrative functions on the entire Bitbucket instance, excluding functions such as backups, imports, and infrastructure settings which are limited to system administrators.

SYSTEM_ADMIN

Administer Bitbucket system

Perform all administrative functions on the entire Bitbucket instance, including functions such as backups, imports, and infrastructure settings.

Last modified on Nov 8, 2022

Was this helpful?

Yes
No
Provide feedback about this article
Powered by Confluence and Scroll Viewport.