What You Can Build
| Use case | What OAuth gives you |
|---|---|
| Customer dashboards | Let users connect Pxxl without sharing passwords or personal API keys. |
| CLI tools | Authorize a local or external CLI with a short-lived OAuth code. |
| Partner apps | Request only the scopes needed for your integration. |
| Internal automation | Pair a user identity with a backend workflow and signed webhook events. |
| Marketplace flows | Connect a user once, then refresh your own integration state from approved scopes. |
Create an OAuth App
Navigate to Dashboard > Integrations and click Create Integration to register your OAuth application. Fill in the fields below:| Field | Purpose |
|---|---|
| Application name | The name users see on the authorization consent screen. |
| Project link | Public URL for your product, dashboard, or integration. |
| Webhook URL | Your backend endpoint that receives oauth.authorized, oauth.denied, and oauth.revoked events. |
| Callback URL | The default redirect URL Pxxl uses after a user authorizes your app. |
| Redirect URIs | The exact URLs that are allowed to receive authorization codes. These must match precisely, including protocol, path, and trailing slash. |
| Scopes | The user data your app is permitted to request. |
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.| Scope | Data returned |
|---|---|
profile | User name and profile picture. |
email | Primary email address and verification state. |
github | Linked GitHub ID, login, name, email, and avatar (when the user has connected GitHub). |
key | Stable public Pxxl user key. |
Authorization URL
Redirect the user to the Pxxl authorization endpoint to begin the OAuth flow:| Query parameter | Description |
|---|---|
response_type | Must be code for the authorization code flow. |
client_id | Your OAuth application’s client ID. |
redirect_uri | Must exactly match one of the redirect URIs registered on your OAuth app. You can also use callback_url as the parameter name for browser flows that already use that convention. |
scope | Space-separated list of scopes to request. |
state | A random, unguessable value you generate. Pxxl returns it unchanged in the callback — validate it before trusting the authorization code. |
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:| Header | Description |
|---|---|
X-Pxxl-Signature | An HMAC-SHA256 signature generated using your app’s hashed client secret as the signing key. Verify this on every request. |
X-Pxxl-Timestamp | A Unix timestamp (in seconds) indicating when the webhook was dispatched. Use this to reject replay attacks older than 5 minutes. |
X-Pxxl-Event | The event name: oauth.authorized, oauth.denied, or oauth.revoked. |
X-Pxxl-Action-Type | The same event name, included for receivers that route by action header. |
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
Authorization redirects back with invalid_redirect_uri
Authorization redirects back with invalid_redirect_uri
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.