OAuth 2.1
Snappy Agents is both the authorization server and the only resource server. Tokens are opaque, stored hashed, and revocable.
| Endpoint | Purpose |
|---|---|
GET /.well-known/oauth-authorization-server |
Metadata (RFC 8414). Also served at /.well-known/openid-configuration for clients that look there. |
GET /.well-known/oauth-protected-resource |
Resource metadata (RFC 9728); referenced from WWW-Authenticate on 401. |
POST /oauth/register |
Dynamic client registration (RFC 7591). |
GET /oauth/authorize |
Browser flow: sign-in (email code or Google) → consent (with read-only switch) → redirect with code. |
POST /oauth/token |
authorization_code (PKCE S256 required) and refresh_token (rotating; reuse revokes the family). |
POST /oauth/revoke |
Revoke a token and its family (RFC 7009). |
POST /oauth/introspect |
Introspection for confidential clients (RFC 7662). |
Scopes
| Scope | Grants | Class |
|---|---|---|
profile |
Email, name, saved addresses | read / write (profile edits) |
catalog:read |
Search, products, availability, collections, address tools | read |
orders:read |
Quotes, checkouts, orders, timelines, SSE | read |
orders:write |
Create quotes and checkouts, cancel, send receipts | write / sensitive-write |
offline_access |
Refresh token | — |
Read-only grants. On the consent screen the user can tick Limit to read-only; orders:write is dropped from the grant. Write endpoints then return 403 with code insufficient_scope and missingScopes, which the agent should turn into "you connected Snappy as read-only; reconnect to buy".
Token lifetimes
| Token | TTL | Notes |
|---|---|---|
| Authorization code | 5 min | Single use; replay revokes every token issued from that grant |
| Access token | 60 min | Bearer header only |
| Refresh token | 30 days | Rotated on each refresh; reuse of an old one revokes the whole family |
Redirect URIs
https only, except http://localhost / 127.0.0.1 for development and custom app schemes. No fragments. Exact match at authorize time.
Client authentication
Public clients use token_endpoint_auth_method: none and PKCE. Confidential clients get a client_secret once at registration and may send it as client_secret_post or HTTP Basic.
Errors
The token endpoint answers RFC 6749 bodies: { "error": "invalid_grant", "error_description": "…" }. The authorize endpoint redirects errors to the registered redirect_uri only after it has been validated; otherwise it renders an HTML error.