Sign in with Postra (OAuth)
Use this when you build an app that works for other Postra users. Each user approves your app once. You get an access token for their workspace. You never see their API key or password.
To automate only your own workspace, you do not need this. Use your API key instead. See Developer settings.
The token starts with pos_. It works wherever an API key works: the Public API, the Node.js SDK and MCP.
At a glance
| Authorisation page | https://app.postra.co.uk/oauth/authorize |
| Token endpoint | https://app.postra.co.uk/api/oauth/token |
| Grant type | authorization_code only |
| Client authentication | client_id and client_secret in the request body |
| PKCE | Optional, S256 only |
| Scopes | None |
| Refresh tokens | None |
1. Create your OAuth app
You need to be the workspace owner or an Admin, on a plan with the API.
- In Postra, open Settings → Developers → Apps.
- Click Create OAuth App.
- Fill in the form and click Create.
| Field | |
|---|---|
| App Name | Required, up to 100 characters. Users see it on the consent screen. |
| Description | Optional, up to 500 characters. Also on the consent screen. |
| Profile Picture | Optional, from your media library. |
| Redirect URL | Required. Postra sends users back here after they decide. |
You get:
- a Client ID, starting with
pca_ - a Client Secret, starting with
pcs_
Copy the secret straight away. Postra shows it only once, after you create the app or rotate the secret. Keep it on your server.
Each workspace can have one OAuth app.
2. Send the user to the authorisation page
https://app.postra.co.uk/oauth/authorize?client_id=YOUR_CLIENT_ID&response_type=code&state=RANDOM_STATE
| Parameter | Required | |
|---|---|---|
client_id |
Yes | Your Client ID |
response_type |
Yes | Must be code |
state |
Recommended | Any value. It comes back unchanged, so you can match the answer to the request. |
code_challenge |
Optional | PKCE: BASE64URL(SHA256(code_verifier)), 43 characters |
code_challenge_method |
With code_challenge |
Must be S256. plain is not supported. |
PKCE makes a stolen code useless: it can only be exchanged with the code_verifier that only your app holds.
3. The consent screen
If the user is not signed in to Postra, Postra asks them to sign in first and then shows the consent screen.
The screen shows your app’s name, description and picture, and says the app will be able to:
- access their integrations and channels
- create and schedule posts on their behalf
- read their post analytics
The user clicks Authorize or Deny.
Only the workspace owner or an Admin can approve. The token acts for the workspace that is selected in Postra at that moment.
4. Handle the redirect
Postra always sends the user to the Redirect URL saved in your app. A redirect_uri parameter is not used.
If the user approves:
https://your-app.example/callback?code=AUTHORISATION_CODE&state=RANDOM_STATE
If the user denies:
https://your-app.example/callback?error=access_denied&state=RANDOM_STATE
Check that state matches what you sent. The code works for 10 minutes and only once.
5. Exchange the code for a token
Call the token endpoint from your server. JSON and application/x-www-form-urlencoded bodies both work.
curl https://app.postra.co.uk/api/oauth/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "authorization_code",
"code": "AUTHORISATION_CODE",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET"
}'
If you sent a code_challenge in step 2, add "code_verifier": the string of 43 to 128 characters you hashed. Send it only then. A code_verifier for a code requested without a challenge is refused.
Answer:
{
"id": "WORKSPACE_ID",
"access_token": "pos_ACCESS_TOKEN",
"token_type": "bearer"
}
id is the Postra workspace the token acts for. Store the token safely on your server.
6. Call the API
Send the token in the Authorization header as it is, without Bearer:
curl https://app.postra.co.uk/api/public/v1/integrations \
-H "Authorization: pos_ACCESS_TOKEN"
With the Node.js SDK, pass the token where you would pass an API key:
const postra = new Postra('pos_ACCESS_TOKEN');
For MCP at https://app.postra.co.uk/api/mcp, send it as Authorization: Bearer pos_ACCESS_TOKEN.
What the token can do
There are no scopes. A token has the same access as the workspace’s API key, which is that of a workspace Admin. All Public API endpoints work, with the same limits.
When a token stops working
Tokens have no fixed expiry. A token works until one of these happens:
- The user removes your app in Settings → Approved apps.
- The same user approves your app again for the same workspace. The new approval replaces the old token.
- The user who approved it leaves the workspace, stops being the owner or an Admin, or is suspended.
- You delete your OAuth app. Every token it issued stops working.
Then the API answers 401 {"msg": "Invalid OAuth token"}. Send the user through the flow again.
While the workspace has no active plan, calls answer 401 {"msg": "No subscription found"}. They work again once it has one.
Managing your app
In Settings → Developers → Apps:
- Edit App changes the name, description, picture and Redirect URL.
- Copy ID copies the Client ID.
- Rotate Secret makes a new Client Secret. The old one stops working for code exchanges at once. Tokens already issued keep working.
- Delete App deletes the app and revokes every token it issued. This cannot be undone.
Errors
From the token endpoint:
| Status | Body | Meaning |
|---|---|---|
400 |
{"error": "unsupported_grant_type"} |
grant_type is not authorization_code |
400 |
{"error": "invalid_grant"} |
The code is unknown, already used, or belongs to another app |
400 |
{"error": "invalid_grant", "error_description": "Code has expired"} |
More than 10 minutes since approval |
400 |
{"error": "invalid_grant", "error_description": "code_verifier does not match the code_challenge"} |
PKCE: missing or wrong code_verifier, or one sent for a code requested without a challenge. The code is not used up. |
400 |
{"message": [...], "error": "Bad Request"} |
A required field is missing or badly formed |
401 |
{"error": "invalid_client"} |
Unknown client_id or wrong client_secret |
429 |
More than 30 requests in 5 minutes |
On the authorisation page, an unknown client_id, a response_type other than code, or a code_challenge without code_challenge_method=S256 shows an error to the user and does not redirect.