Recipes
Client credentials flow
Register a confidential client with client_credentials in allowedGrantTypes, then request tokens without a redirect or authorization code.
Introspect and revoke tokens
const introspection = oauth.introspectToken({
clientId: 'web-app',
token: token.accessToken
});
oauth.revokeToken({
clientId: 'web-app',
token: String(token.refreshToken),
tokenTypeHint: 'refresh_token'
});
Expose JWKS for token verification
const jwks = oauth.getJWKS();
Serve jwks from GET /api/auth/oauth/.well-known/jwks.json (registered automatically) so resource servers can validate access tokens.
Persist consent decisions in a database
import { QAbstractOAuthConsentStore, type QOAuthConsent } from '@quik/oauth-server';
class DBConsentStore extends QAbstractOAuthConsentStore<MyConsentRepository> {
protected persistConsent(consent: QOAuthConsent): QOAuthConsent {
return this.repository.upsert(consent);
}
protected fetchConsent(id: string): QOAuthConsent | undefined {
return this.repository.findById(id);
}
protected findConsent(clientId: string, userId: string): QOAuthConsent | undefined {
return this.repository.findByClientAndUser(clientId, userId);
}
protected removeConsent(id: string): void {
this.repository.deleteById(id);
}
protected clearConsents(): void {
this.repository.deleteAll();
}
protected removeRevoked(now: number): number {
return this.repository.deleteRevokedSince(now);
}
}
Activate custom stores with setOAuthClientStore, setOAuthAuthorizationCodeStore, setOAuthRefreshTokenStore, and setOAuthConsentStore.
Use fixed signing keys in production
Set oauth.server.jwks.signing.privateKeyPem and publicKeyPem explicitly, and set oauth.server.jwks.signing.allowGeneratedFallback to false — otherwise a fresh ephemeral key pair is generated per process start when running outside NODE_ENV=development, invalidating previously issued tokens.
Checklist
- Rotate refresh tokens (
oauth.server.refreshToken.rotateOnUse) unless a client explicitly needs static refresh tokens. - Keep
oauth.server.accessToken.timeToLiveSecondsshort and rely on refresh tokens for long-lived sessions.