Credentials
This is a reference page. It lists the credentials extension.dev holds to run your project, and for each one it says where the credential is stored, how long it lives, and what ends it. Read it before you connect a repository or type a store secret into project settings.
Every statement here describes what the platform does today. Where a claim would need evidence this page cannot show you, the claim is not made. The last section says which claims those are.
The four credentials
| Credential | Where it lives | Lifetime | You end it by |
|---|---|---|---|
| Your sign-in | An encrypted cookie in your browser | The browser session | Signing out |
| Repository access | Requested per operation, held in memory | One hour | Uninstalling the GitHub App |
| Store credentials | Encrypted secrets on your project's build repository | Until you replace or delete them | Deleting them in project settings |
| Access tokens | Nothing stores the token itself | Up to 7 days | Revoking it in project settings |
Your sign-in
You sign in with GitHub. The platform keeps no session table. Your session is an encrypted token in one cookie, __Secure-authjs.session-token, set httpOnly, secure, and sameSite=lax. Because the cookie is httpOnly, JavaScript on the page cannot read it.
Your GitHub access token travels inside that encrypted session token. The session endpoint at /api/auth/session deletes the access token from its response before answering, so the browser is never handed the credential even though the credential is what the cookie carries.
Signing out ends it. Revoking the extension.dev authorization in your GitHub settings ends it at the provider, which is the stronger move.
Repository access
The platform reads and writes your repository through a GitHub App, not through your personal token, and not through a key it stores per user.
Each operation asks GitHub for a fresh token scoped to one repository, with only the permissions that operation needs. A build read gets contents: read and metadata: read. A settings write that has to create an environment gets more. The permission sets are a fixed table in the source, so a caller cannot compose its own.
GitHub issues installation tokens with a one-hour lifetime and returns the expiry alongside the token. The platform reads that expiry and never extends it. The expiry is attached to the client that carries the token as a non-writable property, so no later code can rewrite it.
If GitHub ever returns a token with no expiry, an expiry the platform cannot parse, an expiry already in the past, or a lifetime longer than the documented hour, the request fails instead of proceeding. That is a deliberate trade: the platform refuses a credential whose lifetime it cannot state.
Inside a build
Your build runs in GitHub Actions. It does not carry a stored credential for your source repository. The job proves its identity to the platform with a GitHub OIDC token and exchanges that for a repository token good for one hour, scoped to your source repository, carrying contents: read, deployments: write, and pull_requests: write.
Store credentials
Store credentials are the ones you supply: the Chrome, Edge, Firefox, and Safari keys that let the platform submit on your behalf. They are listed by name on Publishing.
They are encrypted in the platform process, with a public key fetched from GitHub, before they leave it. What GitHub receives is already sealed. Reading them back is not possible: the API the platform uses to check your configuration returns secret names and their last-updated timestamps, never values. This is why a store settings panel can tell you a secret is missing but can never show you the one that is there.
Replacing a value overwrites it. Deleting the secret removes it. Neither leaves a copy in a platform database.
When the console reports which store secrets you have set, it reports whether it could read that list. A listing it could not read is returned as unverified rather than as an empty one, so "no credentials configured" and "I could not see your credentials" are different answers and never the same answer.
What is in reach of a job that runs your code
The credentials that reach a job running your code are your own store credentials, held as repository secrets on your mirror, and no platform credential resolves there.
That is the whole claim, and it is worth reading twice, because the comfortable version of it would be false. Your store credentials are long-lived and they do sit on the same repository that builds your code. What is true is whose credentials they are: yours, and only yours.
Three things hold it up.
- Store credentials become environment variables in the store submission job. That job installs no dependencies from your project and runs no build. It downloads an artifact your build already produced, fetches a pinned submission tool, and talks to the store.
- The job that builds your extension is a different job, in a different workflow. It installs your dependencies and runs their install hooks. No store credential is bound to any step of it.
- The build job checks out with
persist-credentials: false, so git credentials are not written to disk beside the install hooks that run there.
Access tokens
An access token authenticates a machine against one project. See Access tokens for how to mint and use one.
The token is signed, not stored. It carries its own claims and a signature, and the platform verifies the signature rather than looking the value up. Nothing in the platform holds the token itself. What is recorded is a description of it: an id, your label, the lifetime you chose, who issued it, when, when it expires, and whether it was revoked.
A token lives for at least 60 seconds and at most 7 days. There is no longer option.
Revoking one in project settings writes the revocation to that record, and the record is what the project API consults. On that path the check fails closed: a token whose record cannot be found is refused as well.
One path behaves differently and you should know which. The artifact sharing path refuses a token only on an explicit revocation record. If the record store cannot be read at that moment, the request proceeds on the strength of the signature, so that an outage in one store does not stop publishing everywhere. If you need a token dead with certainty, revoke it and confirm the revocation is recorded before you rely on it.
What this page does not claim
- It does not claim that no long-lived credential is in reach of a job that runs your code. Your store credentials are long-lived by design and they sit on the repository that also builds your code. What the section above claims is narrower and checkable: the credentials in reach there are yours.
- The one-hour figure is the lifetime GitHub returns and the platform reads on each request. It is not a measurement of production traffic over time.
- It does not describe the platform's own credentials, which are not yours and are not part of what you configure.
Next
- Access tokens to mint one for CI or an agent
- Publishing for the store credential names and the health check that tells you which one is wrong
- HTTP API for the OIDC exchange CI should use instead of a stored token
