What You Can Build
Create an OAuth App
Navigate to Dashboard > Integrations and click Create Integration to register your OAuth application. Fill in the fields below:Setup Checklist
- Open Dashboard > Integrations.
- Click Create Integration.
- Add a clear application name and logo so users recognize the app during consent.
- Set the public project link for the product requesting access.
- Add your backend webhook URL if you want instant
oauth.authorized,oauth.denied, andoauth.revokedevents. - Add the exact callback URL your backend uses after authorization.
- Add every allowed redirect URI — these must match exactly, including protocol, path, and trailing slash.
- Choose the smallest scope set needed for the first version of your integration.
- Copy the client ID and client secret into your backend secret store.
- Test the authorization URL in a private browser window to verify the full consent flow end-to-end.
Scopes
Request only the scopes your product genuinely needs. Users see each requested scope on the consent screen.Authorization URL
Redirect the user to the Pxxl authorization endpoint to begin the OAuth flow:
If the user is not currently signed in to Pxxl, the platform stores the authorization request, routes them through login, and returns them to the consent screen automatically.
Consent Screen Behavior
The consent screen displays your application name, logo, project link, the requested scopes, and the Pxxl account that will authorize access. If a user has already approved your app with the same or a narrower set of scopes, Pxxl skips the consent screen and redirects them immediately with a fresh one-time code. If you request a new scope the user has not previously approved, they must explicitly authorize the expanded access before Pxxl issues a code.Exchange the Code
Once Pxxl redirects the user back to yourredirect_uri with a code parameter, exchange it for a bearer token from your backend. Authorization codes are single-use and expire quickly — exchange them immediately.
Read User Info
Use the bearer token to fetch the authorized user’s profile data from the userinfo endpoint:OAuth Webhooks
When a user authorizes, denies, or revokes your application, the Pxxl backend dispatches a signed webhook POST to your configured Webhook URL. This lets your backend instantly map the incoming authorization code to a stable Pxxl user ID — so by the time the user lands on your callback URL with thecode parameter, your system already knows who they are and can render the page immediately.
Webhook Headers
Every webhook dispatch includes the following security headers:Event Payloads
oauth.authorized — Sent when a user accepts the consent screen or repeats a previously approved authorization request.
oauth.denied — Sent when a signed-in user rejects the consent screen.
oauth.revoked — Sent when a user removes your app from their connected apps in Pxxl settings.
If you trigger a test webhook using the developer tools endpoint
POST /api/v3/auth/oauth/apps/:id/test-webhook, the event field will be "oauth.test" instead of a production event name.Signature Verification
Verify every incoming webhook before trusting its contents:- Concatenate the
X-Pxxl-Timestampvalue, a period., and the raw request body string:timestamp + "." + rawBody. - Hash your raw
client_secretusing SHA-256 (hex-encoded) to derive the signing key. - Compute the HMAC-SHA256 signature of the concatenated string using that key.
- Perform a constant-time comparison between your computed signature and the
X-Pxxl-Signatureheader value to prevent timing attacks.
Repeat Consent and Automatic Bypass
Once a user has authorized your application with a set of scopes, they will not see the consent screen again when they visit the authorization URL with the same or a narrower subset of those scopes. Pxxl verifies their active authorization status in the database, generates a new one-time code, and redirects them to your callback URL instantly. If you request a new scope the user has not previously approved, the consent screen reappears showing only the new permissions that require explicit approval.Troubleshooting
Token exchange returns bad_verification_code
Token exchange returns bad_verification_code
Authorization codes are short-lived and single-use. Exchange the code immediately from your backend after receiving it in the callback. Never retry the same code after a failed exchange attempt — each retry requires a fresh authorization code.
User sees the consent screen again unexpectedly
User sees the consent screen again unexpectedly
Pxxl skips consent only when the user has already approved your app with the same or a narrower scope set. If you added a new scope to your authorization URL since the last approval, the user must explicitly approve the expanded permissions.
Webhook signature verification fails
Webhook signature verification fails
Make sure you are verifying the raw request body string — not a parsed or re-serialized JSON object. Use the
X-Pxxl-Timestamp header value and your raw client_secret (hashed with SHA-256) as the signing key. Even a single extra byte or re-ordered key in the JSON will produce a different signature.