How to issue API tokens
From docs/how-to/api-tokens.md in the framework repository.
The token guard of @samveys/auth gives each machine client its own token with a list of abilities.
import { auth, ormUserProvider, requireAbility, tokenGuard } from '@samveys/auth'
import { User } from './app/models/user.ts'
const api = tokenGuard({ provider: ormUserProvider(User) })
export const authPlugin = auth({ guards: { api }, default: 'api' })
// Create one, for example from a console command. The plain text is shown once:
const { plainText } = await api.createToken(user, { name: 'ci-deploy', abilities: ['server:update'] })
// Protect a route: 401 without a valid token, 403 without the ability.
router.post('/servers/:id', { use: ['auth:api', requireAbility('server:update')] }, handler)- Clients send
Authorization: Bearer svs_<id>.<secret>. - Only a SHA-256 of the secret is stored, in
samveys_api_tokens. SHA-256 is correct here because the secrets are long and random, unlike passwords, and checking them stays fast on every request. The comparison runs in constant time. - A token without
server:updateis refused with 403SVS_E094on a route that requires it. An unknown, revoked, or expired token gets 401SVS_E093. revokeToken(id)revokes one token.revokeAllTokens(user)revokes every token of a user.
Policies.
- An ability says what a token may do in general. A policy says whether this user may act on this record.
- Wrap the handler with
guarded(policy, 'update', loadPost, handler). The check then runs right before the handler, so it still holds when someone forgets a middleware.