Developers · 03
OAuth
Let an addon ask an organisation for access instead of asking an admin to paste a token.
When to use it
Use OAuth when other organisations install your addon. They approve it on a consent screen that names you and lists the scopes, and your addon receives the token directly.
Use a hand-minted token when the integration is for your own organisation only. See Authentication.
1. Register a client
Addons → Develop → your listing → OAuth client. Add every redirect URI you use and create the client.
The client secret is shown once. Redirect URIs are matched exactly, so https://app.example/cb will not accept https://app.example/cb/done. HTTPS only, except localhost and 127.0.0.1 for development.
2. Send the member to the consent screen
GET /oauth/authorize
?client_id=ptc_…
&redirect_uri=https://app.example/cb
&response_type=code
&scope=projects:read specs:read
&state=<random per request>state is yours to generate and check on the way back. Only an org admin can approve, and only scopes the API defines are accepted.
For a public client, add code_challenge and code_challenge_method=S256.
3. Handle the redirect
On approval the member returns to your redirect URI with code and your state.
https://app.example/cb?code=ptac_…&state=<yours>
On refusal you get error=access_denied and the same state. Compare the returned state to the one you issued before doing anything else.
4. Exchange the code
curl -X POST https://<your-host>/api/v1/oauth/token \
-d grant_type=authorization_code \
-d code=ptac_… \
-d redirect_uri=https://app.example/cb \
-d client_id=ptc_… \
-d client_secret=ptcs_…{ "access_token": "ptk_live_…", "token_type": "Bearer", "scope": "projects:read specs:read" }Codes are single use and expire in minutes. redirect_uri must match the one you authorized with. With PKCE, send code_verifier instead of client_secret.
The token works on every /api/v1 endpoint exactly like a hand-minted one.
Errors
Failures return an OAuth error object with a 400, or 401 for client authentication.
error | Means |
|---|---|
invalid_client | Unknown client, or the secret did not match |
invalid_grant | Code expired, already used, issued to another client, or the redirect did not match |
invalid_request | A required parameter is missing |
unsupported_grant_type | Only authorization_code is supported |
access_denied | The member cancelled |
A 429 means you are sending too fast. Honour the Retry-After header and back off rather than retrying immediately.
Revocation
An admin can revoke a grant from Admin → Integrations → Authorized addons. That immediately kills every token the grant issued, and calls start returning 401.
Treat a sudden 401 as a revoked grant and start the flow again rather than retrying.
Before you publish
Publishing requires a contact email and acceptance of the publisher agreement. The email is private, and we use it when your addon starts failing or gets reported.