Developers · 03

OAuth

Let an addon ask an organisation for access instead of asking an admin to paste a token.

Raw markdown

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

http
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

bash
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_…
json
{ "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.

errorMeans
invalid_clientUnknown client, or the secret did not match
invalid_grantCode expired, already used, issued to another client, or the redirect did not match
invalid_requestA required parameter is missing
unsupported_grant_typeOnly authorization_code is supported
access_deniedThe 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.