Apps & OAuth overview
Register OAuth clients and let Feeef users grant your integration scoped access.
Feeef implements OAuth 2.0 authorization code (RFC 6749) with PKCE (RFC 7636), plus token revocation (RFC 7009) and introspection (RFC 7662). Users grant your application access on the familiar consent screen; your app receives a token carrying exactly the scopes they approved.
The two hosts
| Host | Role | Endpoints |
|---|---|---|
accounts.feeef.org | Human-facing: sign-in + consent UI | GET /oauth/authorize |
api.feeef.org/v1 | Machine-facing: token operations | POST /oauth/token, /oauth/revoke, /oauth/introspect |
The address bar shows the accounts domain during authorization — like signing in with Google. (Opening authorize on the API host still works; it 302-redirects to accounts.)
Apps
An app is your registered OAuth client. Manage apps in the dashboard or via the API:
| Method | Path | Notes |
|---|---|---|
POST | /apps | Create — returns clientId and clientSecret once |
GET | /apps | List your apps (paginated, supports filterator) |
GET | /apps/:id | Detail |
PUT | /apps/:id | Update name, redirectUris, scopes, active, logoUrl, tokenEndpointAuthMethod |
DELETE | /apps/:id | Delete (revokes nothing retroactively — revoke tokens separately if needed) |
POST | /apps/:id/regenerate-secret | New secret, shown once; the old secret stops working immediately |
App registration fields:
| Field | Rules |
|---|---|
name | 2–100 chars, shown on the consent screen |
redirectUris[] | Exact-match allowlist, absolute URIs, no wildcards |
scopes[] | The maximum scopes the app may ever request — see Scopes |
logoUrl | Optional public HTTPS image, shown as the consent-screen avatar |
tokenEndpointAuthMethod | client_secret_post (confidential, default) or none (public + PKCE) |
active | Inactive apps refuse new authorizations |
Public vs confidential clients
| Client type | tokenEndpointAuthMethod | Token request | PKCE |
|---|---|---|---|
| Confidential — server-side web app, backend job | client_secret_post | Sends client_secret | Recommended |
| Public — SPA, mobile app, CLI | none | No secret | Required (S256) |
Never embed a client secret in code you ship to users (browser bundles, mobile apps, CLIs).
If your code runs on the user's device, register a public client and use PKCE. The official
@feeef.dev/cli is a public client.
Token properties
A successful exchange returns:
{
"access_token": "oat_...",
"token_type": "Bearer",
"expires_in": 7776000,
"scope": "auth store.read products.read"
}- Tokens are opaque, live 90 days, and carry the consented scopes as abilities.
- The token row records the issuing
app_id— this is what gates per-user app data and lets users see "connected apps". - There are no refresh tokens — on
401, run the flow again.
Lifecycle endpoints
| Purpose | Call |
|---|---|
| Revoke a token (sign-out) | POST /oauth/token … POST /oauth/revoke with form body token=... → { "revoked": true } |
| Check a token | POST /oauth/introspect with token=... → { "active": true, "scope": "...", "exp": ... } |
| User-side: list authorized apps | GET /users/auth/connected-apps (shown in the dashboard) |