Bitbucket App Passwords Are Gone: Three Usernames, One Token
App passwords were removed on 28 July 2026. The migration is a thirty-minute swap per system, except for the part nobody documents in one place: which username goes with which credential. There are three answers and picking the wrong one returns 401 with a perfectly good token.
Bitbucket Cloud app passwords were removed on 28 July 2026, at the end of escalating brownouts that ran from 9 June. Creation had already been switched off back in September 2025, so if you went looking for the button recently and could not find it, that is why.
If something of yours is still broken, it is probably not the token. It is the username.
Three credentials, three usernames
App passwords authenticated with your plain Bitbucket username everywhere, for Git and for the REST API alike. Nothing that replaces them does that, and the replacements do not agree with each other either.
| Credential | Git over HTTPS | REST API |
|---|---|---|
| Atlassian API token | your Bitbucket username, or x-bitbucket-api-token-auth | your Atlassian account email |
| Repository or workspace access token | x-token-auth | x-token-auth |
| App password | your Bitbucket username | your Bitbucket username |
So a find-and-replace that swaps the secret value and leaves the username alone gives you a 401, and you will spend an hour convinced the token is bad. It is not.
Two details in that table are worth pulling out. If you use your real Bitbucket username with an API token for Git, Atlassian’s docs warn that it is case sensitive and has to match your account settings page exactly, which is a fun one to debug. And repository and workspace access tokens use a completely different magic string from API tokens, x-token-auth rather than x-bitbucket-api-token-auth, which is the single most common thing people get wrong when they follow one doc page for the token and another for the git command.
Bitbucket also now accepts Bearer authentication for API tokens rather than only Basic, so an integration sending Authorization: Bearer <token> works and sidesteps the username question entirely for REST calls. Existing Basic-auth integrations keep working.
Person or machine
The choice between the two credential types is not about scopes. It is about what happens when somebody leaves.
git config user.email.A Jenkins job that builds one service does not need a credential that can read every repository in the workspace, and it should not stop working three weeks after the engineer who created it leaves. That is the whole argument for repository access tokens, and it is a better argument than the scope granularity.
Workspace and project access tokens widen the same idea to a whole workspace or project, and they are a Premium feature. Atlassian says so on the page itself. On Standard the fallback is a repository access token per repository, which is more objects to manage and also, honestly, a better security posture.
Scopes: do not copy admin everywhere
Scopes are verbose but predictable, in the shape verb:noun:bitbucket: read:repository:bitbucket, write:pullrequest:bitbucket, read:pipeline:bitbucket, the three webhook ones, and so on.
A build that only clones and compiles needs read:repository:bitbucket and nothing else. A bot that comments on pull requests needs read:repository:bitbucket plus write:pullrequest:bitbucket, and specifically does not need write on the repository. Your own laptop wants read and write on repository plus write on pull requests.
The temptation under a deadline is to tick every box, ship, and tighten later. Later does not come, and a two-week deadline turns into a permanent over-privileged credential. A read-only token costs the same thirty seconds to create.
Cleaning up local Git
If you embedded an app password directly in a remote URL, and plenty of people did because it was the path of least resistance, that secret is in your shell history and in .git/config.
git remote -v # if a secret is visible here, it is also in your history
git remote set-url origin https://bitbucket.org/myworkspace/myrepo.git
Then let a credential helper hold the token, and delete the stale entry first, because otherwise the helper keeps handing Git a dead credential and you keep getting the same failure.
git config --global credential.helper osxkeychain
git credential-osxkeychain erase <<EOF
protocol=https
host=bitbucket.org
EOF
On Linux with credential.helper store, check ~/.git-credentials for an existing bitbucket.org line and delete it. On Windows, cmdkey /list, find the bitbucket.org entry, delete it, re-authenticate. Same failure mode all three ways: the helper caches the old credential and re-authentication never gets triggered.
For your own machine, SSH keys sidestep this entire category. App password deprecation never touched SSH. The reason to bother with HTTPS tokens at all is that CI systems and package managers frequently cannot do SSH cleanly.
The systems that break quietly
Bitbucket Pipelines is mostly fine because it has its own variables and OIDC. What breaks is a pipeline step that shells out to curl against the Bitbucket API with a hardcoded credential, which is a depressingly common way to tag a release or post a comment.
Jenkins is the messy one. The Bitbucket Branch Source plugin is particular about credential types and there have been reports of tokens failing specifically on multibranch pipelines. Test in a scratch job against your actual plugin version rather than trusting any writeup, including this one.
Pull mirrors are the ones that page nobody. A GitLab pull mirror from Bitbucket holds a stored HTTPS credential, and when it stops working the mirror does not fail loudly, it just goes stale. Go and look at the mirror status page rather than waiting to be told.
Composer is the case that exposed the design problem. It stores one credential pair and uses it for both cloning and API metadata lookups, so a scheme that wants different usernames for those two things does not fit its config shape cleanly. If you use Composer with private Bitbucket repositories, check the current state of its auth handling rather than assuming your block still works.
And anywhere a Terraform provider or a source-control connection holds credentials, that is an app password waiting to be found. Oracle published its own deprecation notice for Resource Manager’s Bitbucket Cloud connections, which is a decent indicator of how far this reached.
Expiry is the new failure mode
App passwords lasted forever. API tokens expire, and workspace administrators can enforce a maximum lifetime.
That is the correct security posture and it will cause an outage in about a year if nothing changes. A credential that never expired needed no process. A credential that expires needs someone to notice on a specific date, and a plugin’s credential list will not tell them.
If your CI secrets live only in a Jenkins credential store, nobody learns a token is expiring until a build dies. Somewhere with expiry metadata and alerting is better, and I went through the options for that earlier this year. Failing that, a calendar reminder two weeks before each expiry is unglamorous and works. The teams that get burned by rotation are the ones who assumed some system would remind them.
Dates, username requirements, and the Premium restriction on workspace tokens came from Atlassian’s own documentation and deprecation notices, checked on 23 August 2026.