The identity provider
Other people's software signs in to yours. You are issuing the tokens now, and the specification is not optional.
OAuth 2.1 with PKCE, refresh rotation, a device flow for things with no browser, and discovery so clients configure themselves. Registered clients, scopes, and an audit trail come with it.
This is a real commitment. Take it when integrators are asking for it, not because it sounds like the mature choice — everything in §26 is still true underneath, and you now own an expiry sweep as well.
What you are carrying
@atlas/oauthAuthorize, token, revoke, device, discovery, client admin.
@atlas/authThe human login the authorize endpoint sits behind.
@atlas/dbClients, codes, refresh tokens, device codes.
@atlas/securityRate limits and the audit log you will be asked for.
Start it
bun add @wess/atlas
What it looks like
import { oauthRoutes, sweepExpired } from "@atlas/oauth"
import { requireAuth } from "@atlas/auth"
const cfg = {
db,
secret: config.secret,
scopes: ["profile", "email", "offline_access"],
loadUser: (db, userId) => findUserById(db, userId),
buildAccessTokenClaims: (user) => ({ sub: String(user.id), email: user.email }),
// The consent screen is a normal authenticated page; the client admin is not.
requireUser: requireAuth({ secret: config.secret }),
requireAdmin: requireStaff,
}
export const routes = oauthRoutes(cfg, { basePath: "/oauth", adminBasePath: "/oauth/clients" })
// Codes, refresh tokens, and device codes all expire. Nothing deletes them
// for you, and the tables only grow.
setInterval(() => void sweepExpired(cfg), 15 * 60_000)