Key facts
| Flow | OAuth 2.0 authorization code with PKCE |
| Use case | Sign in with Plugsky and access a user's workspace on their behalf |
| Scopes | Request the narrowest list, e.g. models read plus chat write |
| Token handling | Server-side code exchange; refresh tokens stored encrypted |
| PKCE | code_verifier and code_challenge (S256) protect public clients |
| Revocation | Users disconnect the app from their Plugsky workspace |
| Personal keys | Bearer sk-live- keys remain the right choice for first-party services |
| Product status | Live |
TL;DR
- Use the authorization-code flow with PKCE — not implicit, not password grants.
- Exchange the code server-side; keep refresh tokens encrypted at rest.
- Ask for minimal scopes and explain each one on the consent screen.
- Validate state to block CSRF, and pin redirect URIs exactly.
- Give users a disconnect path that revokes your app's access.
How it works, step by step
- Register the application with Plugsky and record the client ID and exact redirect URI.
- Generate a PKCE code_verifier, hash it with S256, and keep it for the exchange.
- Redirect the user to the authorization endpoint with state, scopes and code_challenge.
- On callback, verify state, then exchange the code plus verifier for tokens server-side.
- Store refresh tokens encrypted; keep access tokens short-lived and in memory where possible.
- Call the API with the granted scope and handle 403 by requesting a wider scope only when justified.
- Implement revocation and a disconnect flow, then test deprovisioning end to end.
Try it yourself
Open the OpenAI-compatible API tester →
When to use OAuth versus API keys
Two identities are in play. First-party services act as your organisation: they use scoped sk-live- keys, one per service and environment, rotated quarterly. Third-party SaaS apps act as the user: they need OAuth so the user consents, and so access can be revoked without sharing credentials. If your product runs inside the customer's workspace as an installed app, OAuth is the correct model even if a key would be simpler.
The PKCE flow, step by step
- Generate a random
code_verifierand derivecode_challenge = BASE64URL(SHA256(verifier)). - Redirect to the authorization endpoint with client ID, redirect URI, scopes, state and the code challenge.
- The user authenticates and consents; Plugsky redirects back with an authorization code.
- Your backend verifies
stateand exchanges the code pluscode_verifierfor tokens. - Call the API with the access token; refresh when it expires; re-consent only when scopes change.
PKCE removes the client secret from public clients such as mobile and single-page apps by proving the same client that started the flow is finishing it.
Scopes, storage and revocation
- Least privilege: request model listing and the specific write scopes your feature needs. Every extra scope is a consent-screen objection.
- Token storage: refresh tokens encrypted at rest with access limited to the service that uses them; access tokens short-lived and out of logs.
- Redirect URI pinning: exact-match allowlists only, no wildcards; validate on the server as well as the client.
- CSRF: a high-entropy
statebound to the user session, verified on callback. - Revocation: users can disconnect the app; your system must handle the next 401 by prompting reconnection rather than looping retries.
Failure modes to test before launch
Test the unhappy paths deliberately: user denies consent; state mismatches; code replay; expired refresh token; scope removed after a plan change; and the user disconnects the app mid-session. Each should produce a clear re-authentication prompt, not a retry storm. Log the client ID, user reference and granted scopes — never tokens — so support can diagnose without exposing secrets. For enterprise customers, document how OAuth access interacts with SSO and SCIM deprovisioning so access reviews cover both human and app grants.
Honest comparison
| Capability | Plugsky OAuth | Shared API key | Custom credential sharing |
|---|---|---|---|
| User consent | Explicit consent screen with scopes | None | Manual off-platform |
| PKCE support | Authorization code plus S256 challenge | Not applicable | You build it |
| Revocation | User disconnects the app | Rotate the shared key | Ad hoc |
| Scope limits | Narrow scopes per app | Whole key's scope list | Unbounded |
| Audit | Grants and usage attributable | One key, many actors | Untraceable |
| Fit for third-party SaaS | Designed for it | An anti-pattern | Risky |
Frequently asked questions
Does Plugsky support OAuth 2.0?
Yes. The docs document the authorization-code flow with PKCE for SaaS apps that offer Sign in with Plugsky or access a user's workspace on their behalf.
Should my SaaS app use OAuth or an API key?
If the app acts for the user in their workspace, use OAuth. If your own service calls the API for your organisation, use scoped sk-live- keys per service and environment.
What is PKCE and why does it matter?
PKCE binds the authorization request to the token exchange with a code verifier and S256 challenge, so a stolen code cannot be redeemed by another client. It is required for public clients like mobile and SPAs.
Which scopes should I request?
Only the scopes your features actually use, for example model listing plus chat write. Broad scopes slow consent and widen the impact of a compromise.
How should I store refresh tokens?
Encrypt them at rest, restrict access to the service that needs them, and keep them out of logs and client-side storage. Rotate on refresh where supported.
How do users revoke access?
Users disconnect the app from their Plugsky workspace. Your code should treat the resulting 401 as a signal to ask for reconnection instead of retrying.
Does OAuth work for mobile and single-page apps?
Yes, with PKCE and no client secret. Send the authorization request from the client, but perform the code exchange on your backend when one exists.
How does OAuth interact with enterprise SSO?
SSO governs human sign-in; OAuth governs app access. Include both in access reviews and confirm that deprovisioning revokes app grants as well as user sessions.