Authentication & authorization
DaloyJS doesn't bundle a user database or login UI, instead, it ships primitives that make it easy to plug in a hosted identity provider (IdP). Your API receives a bearer token, verifies it with the provider's JWKS or SDK, and gates routes by scope, role, or organization. The pages in this section show how to wire up the seven most common IdPs.
New to this? Start with Auth architecture: where DaloyJS fits in OAuth2 & OpenID Connect. It explains why DaloyJS is a resource server (it verifies tokens, it does not issue them), how that compares to .NET and Duende IdentityServer, whether you actually need Auth0/Okta/Clerk or can self-host an open-source IdP, and the two architectures we recommend.
Supported providers
- AWS Cognito: pay-as-you-go user pools with hosted sign-in. Use
aws-jwt-verifyto verify access and ID tokens with zero runtime dependencies; runs on Node, edge, and Lambda. - Microsoft Entra ID (MSAL): enterprise SSO for Microsoft 365 / Azure AD users. Verify tokens with the OIDC JWKS using
jose; acquire downstream tokens with@azure/msal-nodewhen needed. - Auth0: developer-friendly IdP with universal login, MFA, and rich rule engine. Verify access tokens with
joseagainst your tenant's issuer URL. - Okta: workforce identity with custom authorization servers and granular policies. Use the official
@okta/jwt-verifierfor access and ID tokens. - Clerk: modern, embeddable authentication with user, organization, and billing primitives. Use
@clerk/backendauthenticateRequest()to authenticate anyRequest. - LoginRadius: customer identity, social login, registration, and profile APIs. Use
loginradius-sdkto validate LoginRadius access tokens and load profiles from a Node-style DaloyJS runtime. - Better Auth: self-hosted authentication for email/password, OAuth, sessions, and plugins. Mount its standard
Request → Responsehandler under DaloyJS and guard API routes withauth.api.getSession().
Runtime compatibility at a glance
| Provider | Node / Bun / Deno | Cloudflare Workers | Vercel | AWS Lambda |
|---|---|---|---|---|
AWS Cognito (aws-jwt-verify) | Yes | Yes (Web Crypto) | Yes | Yes |
Entra ID (jose) | Yes | Yes | Yes | Yes |
Auth0 (jose) | Yes | Yes | Yes | Yes |
Okta (@okta/jwt-verifier) | Yes | No (Node-only) | No | Yes |
Clerk (@clerk/backend) | Yes | Yes | Yes | Yes |
LoginRadius (loginradius-sdk) | Yes (Node-style) | No | Node functions only | Yes |
Better Auth (better-auth) | Yes | Depends on database adapter | Yes | Yes |
Common pattern
Each provider page implements the same three steps: install the verifier SDK, register a DaloyJS plugin that decorates the request context with an auth object, then guard routes with a small middleware that requires a token (and optional scopes).
- 01Install the verifier SDKpnpm add <provider-sdk>
- 02Register an auth plugindecorates ctx with a verifier
- 03Guard routesrequireAuth(...scopes)
// src/plugins/auth.ts
import type { App, Middleware } from "@daloyjs/core";
export interface Principal {
sub: string;
scopes?: string[];
claims: Record<string, unknown>;
}
export interface TokenVerifier {
verify(token: string): Promise<Principal>;
}
export function authPlugin(verifier: TokenVerifier) {
return {
name: "auth",
register(app: App) {
app.decorate("verifier", verifier);
},
};
}
export function requireAuth(...requiredScopes: string[]): Middleware {
return async (ctx, next) => {
const header = ctx.request.headers.get("authorization") ?? "";
const [scheme, token] = header.split(" ");
if (scheme?.toLowerCase() !== "bearer" || !token) {
return ctx.problem(401, "unauthorized", "Missing bearer token");
}
try {
const principal = await ctx.state.verifier.verify(token);
if (requiredScopes.length) {
const scopes = principal.scopes ?? [];
const ok = requiredScopes.every((s) => scopes.includes(s));
if (!ok) return ctx.problem(403, "forbidden", "Insufficient scope");
}
ctx.state.principal = principal;
return next();
} catch {
return ctx.problem(401, "unauthorized", "Invalid or expired token");
}
};
}
declare module "@daloyjs/core" {
interface AppState {
verifier: TokenVerifier;
principal?: Principal;
}
}Each provider page implements TokenVerifier with the official SDK so the rest of your application stays IdP-agnostic.
Security checklist
- Always verify the signature. Never trust an unverified JWT, decode-only utilities are for debugging. Use the provider's JWKS endpoint with key caching and automatic rotation (every SDK on the following pages handles this).
- Check
issandaud. Pin the expected issuer URL and audience/client ID. A correct signature on the wrong audience is still a token confusion attack. - Authorize, don't just authenticate. A valid token only proves the caller is who they say they are. Enforce scopes, roles, or organization membership for every privileged action.
- Use TLS everywhere. Bearer tokens are plaintext-equivalent. Require HTTPS and set the
secureHeadersmiddleware (Strict-Transport-Security). - Rate-limit token-issuing routes. Login redirects, token-exchange endpoints, and any introspection passthroughs should go through
rateLimit(or the Redis store) so abuse can't drive cost or lock out users. - Protect cookies and CSRF. If you also use session cookies (for an admin panel, say), enable CSRF and use
SameSite=Lax+Secure+HttpOnlyvia the built-in session middleware.