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!
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:
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
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
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.