Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

How do you handle rotating OAuth 2.0 (3LO) refresh tokens in Bitbucket Pipelines?

Konrad
July 6, 2026

Hi everyone,

I'm running into an issue with OAuth 2.0 (3LO) authentication in our E2E tests and I'm wondering how others have solved it.

Our Playwright E2E tests use our app's REST API, which authenticates via Atlassian OAuth 2.0 (3LO). The authentication flow relies on a refresh token to obtain a new access token. As expected, every refresh request returns a new refresh token, so the token needs to be persisted for the next execution.

This works fine locally, but I'm struggling with running the tests in Bitbucket Pipelines.

The problem is that after each pipeline run I need to persist the newly returned refresh token somewhere. Bitbucket repository variables are read-only from the pipeline's perspective (at least they don't seem intended to be used as mutable storage), so I can't simply update the stored refresh token for the next pipeline run.

Has anyone faced a similar problem?

Some questions I have:

  • How do you handle rotating refresh tokens in CI/CD?

  • Is there a recommended approach for Atlassian 3LO authentication in automated pipelines?

  • Do you use an external secret store (AWS Secrets Manager, Vault, etc.), or is there another approach I'm missing?

  • Is there a better authentication mechanism for automated E2E tests that avoids this problem altogether?

I'd really appreciate hearing how others have implemented this.

Thanks!

2 answers

1 accepted

0 votes
Answer accepted
Viswanathan Ramachandran
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Champions.
July 6, 2026

hi @Konrad 

I think the root cause is that 3LO isn’t really designed for unattended CI/CD workloads it’s built around delegated user authentication, so refresh token rotation is expected.

A few approaches you can consider to work well:

  • Don’t use 3LO in CI unless you’re specifically testing the OAuth flow. If your E2E tests are validating your application’s functionality rather than Atlassian’s authentication, it’s often better to isolate the auth layer or use an alternative authentication mechanism where possible.
  • Store the refresh token in an external secrets manager. This is probably the cleanest production-grade solution. Services like AWS Secrets Manager, HashiCorp Vault, Azure Key Vault, or GCP Secret Manager are all suitable for this.
  • Introduce a small token broker/auth service. Instead of every pipeline managing refresh token rotation, a lightweight internal service can own the OAuth lifecycle and simply return a valid access token to your tests. That keeps token rotation logic in one place and avoids pipeline state management entirely.

One thing I’d avoid is trying to use Bitbucket repository variables as mutable storage. They’re intended for configuration rather than runtime state, and updating them from pipelines can become problematic, if multiple pipeline runs overlap and race to update the latest refresh token.

Out of curiosity, are your playwright tests validating the OAuth flow itself, or are they primarily testing your app after authentication? That distinction would influence the recommended approach. If it’s the latter, I’d lean towards abstracting authentication away from the tests and letting the pipeline consume a valid access token rather than owning the refresh token lifecycle.

The documentation below clearly explains how rotating refresh tokens work and that applications must always persist the newly returned refresh token, but it doesn’t describe a recommended CI/CD strategy or where that token should be stored.

https://developer.atlassian.com/cloud/jira/platform/oauth-2-3lo-apps/?utm_source 

Konrad
July 7, 2026

Thanks for the explanation - that makes sense.

In our case we're not testing the OAuth flow itself. We only use 3LO because our backend API requires it when preparing test data before running Playwright tests.

I understand that an external secret manager or token broker would solve the problem, but I was wondering whether Atlassian has an officially recommended approach for CI/CD scenarios like this but it seems there is no such recommendation. 

Viswanathan Ramachandran
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Champions.
July 7, 2026

Glad it helps, yes lets see what's in for Atlassian's strategy. 

On this note, Atlassian close competitors have well-defined CI/CD security recommendations, and both strongly discourage storing tokens directly in repositories, pipeline files, or source code.

The preferred approach is to use platform’s built-in secret management (ex: Bitbucket Repository/Workspace/Deployment Variables) and for enterprise and regulated environments, integrate with an external secrets manager. Where supported, using OIDC/workload identity with short-lived credentials is considered the most secure pattern over long-lived API tokens.

If your organization uses Atlassian Atlassian Guard, you can also:

  • Use dedicated automation (service) accounts instead of personal accounts.
  • Restrict API token usage with organizational policies where available.
  • Audit authentication events alongside pipeline activity.
  • Apply least-privilege permissions to the automation account.

 

 

Like Konrad likes this
0 votes
Gabriela
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Champions.
July 6, 2026

Hi @Konrad, welcome to the community. For E2E tests that just hit the REST API as a user, drop 3LO in CI and the rotating-token problem disappears. Use Basic auth with an Atlassian API token — `Authorization: Basic base64("email:api_token")` — it doesn't rotate, so it sits fine in a secured Bitbucket repository variable. One caveat: API tokens now carry a max 1-year expiry, so you swap it yearly, not per run. If you truly need 3LO (per-user scoped tokens, or testing the flow itself), your instinct's right: each refresh returns a new single-use token and a pipeline can't rewrite its own repo variable, so an external store like Secrets Manager is the move. Basic auth for REST APIs

Konrad
July 6, 2026

Unfortunately, in our case we're not calling Jira's REST API directly. The Playwright tests call our application's backend API, which validates an Atlassian 3LO access token and uses it to act on behalf of the authenticated user.

So replacing 3LO with Basic auth isn't something we can do without changing our application's authentication model.

It sounds like, if we continue using 3LO, an external secrets manager (or a token broker) is indeed the recommended approach.

Gabriela
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Champions.
July 8, 2026

Yeah, if your backend expects an Atlassian 3LO access token then Basic auth is off the table without touching your auth model, so external store it is. Two things that bit me when I wired this up. The rotation is single-use — the moment you refresh, the old refresh token is dead and you get a new one valid for another 90 days, so the pipeline has to write that new token straight back to the store or the next run fails with invalid_grant. And watch concurrent runs: two pipelines grabbing the same refresh token at once will race, one wins and the other's token is already invalidated. A small token broker sidesteps that, since it holds the refresh token itself and just hands each run a short-lived access token. Also keep in mind the refresh token dies after 90 days of no use, so a repo that goes quiet over a long break will need a fresh authorize before pipelines run green again.

Like Konrad likes this

Suggest an answer

Log in or Sign up to answer
DEPLOYMENT TYPE
CLOUD
PRODUCT PLAN
FREE
PERMISSIONS LEVEL
Product Admin Site Admin
TAGS
AUG Leaders

Atlassian Community Events