Proxy Client¶
SentinelAuth is the browser auth client for proxy mode. Sentinel manages the full OAuth2 + PKCE redirect flow, token exchange, and refresh. You get a single access token + refresh token pair.
For the recommended authz mode, see AuthZ Client.
Setup¶
import { SentinelAuth } from '@sentinel-auth/js'
const auth = new SentinelAuth({
sentinelUrl: 'http://localhost:9003',
})
| Option | Type | Default | Description |
|---|---|---|---|
sentinelUrl |
string |
required | Base URL of the Sentinel service |
redirectUri |
string |
${origin}/auth/callback |
OAuth redirect URI |
storage |
TokenStore |
MemoryStore |
Token storage backend |
autoRefresh |
boolean |
true |
Refresh tokens before expiry |
refreshBuffer |
number |
60 |
Seconds before expiry to trigger refresh |
How it works¶
1. auth.login('google') -> PKCE + CSRF state, redirect to Sentinel
2. Sentinel -> Google -> callback -> ?code=...&state=...
3. auth.verifyCallbackState() -> verify CSRF state
4. auth.getWorkspaces(code) -> list available workspaces
5. auth.selectWorkspace(code, id) -> exchange code + PKCE verifier for tokens
6. Access + refresh tokens stored
Methods¶
login(provider)¶
Generate PKCE verifier and CSRF state, redirect to Sentinel's login endpoint.
verifyCallbackState()¶
Verify the state parameter from the callback URL. Call before processing the auth code. Throws on mismatch.
getWorkspaces(code)¶
Fetch available workspaces for the auth code.
selectWorkspace(code, workspaceId)¶
Complete token exchange with PKCE verifier. Stores access + refresh tokens.
getToken() / getUser() / isAuthenticated¶
const token = auth.getToken() // raw access token string
const user = auth.getUser() // SentinelUser | null
if (auth.isAuthenticated) { /* */ } // non-expired token exists
fetch / fetchJson¶
Automatic Authorization: Bearer header. On 401, refreshes and retries.
getProviders()¶
Fetch available OAuth providers from Sentinel.
refresh() / logout() / onAuthStateChange(cb) / destroy()¶
await auth.refresh() // manual refresh (auto by default)
auth.logout() // clear tokens, notify listeners
const unsub = auth.onAuthStateChange((user) => { /* */ })
auth.destroy() // clean up timers
Token storage¶
| Backend | Persistence |
|---|---|
MemoryStore (default) |
Lost on page refresh |
LocalStorageStore |
Survives refresh, shared across tabs |
SessionStorageStore |
Cleared when tab closes |
import { SentinelAuth, LocalStorageStore } from '@sentinel-auth/js'
const auth = new SentinelAuth({
sentinelUrl: '...', storage: new LocalStorageStore(),
})
Complete example¶
import { SentinelAuth, LocalStorageStore } from '@sentinel-auth/js'
const auth = new SentinelAuth({
sentinelUrl: 'http://localhost:9003',
storage: new LocalStorageStore(),
})
// Login page
await auth.login('google')
// Callback page (/auth/callback)
const code = new URLSearchParams(window.location.search).get('code')
if (code) {
auth.verifyCallbackState()
const workspaces = await auth.getWorkspaces(code)
if (workspaces.length === 1) {
await auth.selectWorkspace(code, workspaces[0].id)
window.location.href = '/dashboard'
}
}
// Authenticated requests
const notes = await auth.fetchJson<Note[]>('/api/notes')
How it differs from AuthZ mode¶
Proxy (SentinelAuth) |
AuthZ (SentinelAuthz) |
|
|---|---|---|
| OAuth flow | Sentinel proxies (PKCE, redirect) | You configure IdPs, SDK redirects directly |
| Token exchange | code + PKCE verifier via /auth/token |
IdP token via /authz/resolve |
| Tokens | Access + refresh (single JWT) | IdP token + authz token (dual) |
| Headers | Authorization: Bearer |
Authorization + X-Authz-Token |
| Refresh | Uses refresh token | Re-resolves IdP token |