Auth Overview
Built-in auth middleware provides bridge patterns for WordPress REST routes.
Available middleware
BetterRoute\Middleware\Jwt\JwtAuthMiddlewareBetterRoute\Middleware\Jwt\Rs256JwksJwtVerifier(v0.6.0) — RS256/ES256 verifier backed by JWKS; see JWKS (RS256 / ES256)BetterRoute\Middleware\Jwt\HttpJwksProvider/StaticJwksProvider(v0.6.0)BetterRoute\Middleware\Auth\BearerTokenAuthMiddlewareBetterRoute\Middleware\Auth\HmacSignatureMiddleware(v0.6.0) — HMAC request signatures with replay-window enforcement; see HMAC Request SignaturesBetterRoute\Middleware\Auth\CookieNonceAuthMiddlewareBetterRoute\Middleware\Auth\ApplicationPasswordAuthMiddlewareBetterRoute\Middleware\Auth\WpClaimsUserMapperBetterRoute\Middleware\Auth\OwnershipGuardMiddleware(v0.5.0) — see Ownership guards
Context propagation
On success, middleware writes auth context attributes:
auth(provider, userId, subject, scopes)- optionally
claims,userId,user,scopes hmac(v0.6.0) —keyIdandalgorithmafter successful HMAC signature verification. (v1.1.0) HMAC verification now also writes the sharedauthattribute (provider: 'hmac',subject: <keyId>), so identity-scoped middleware sees HMAC callers like any other authenticated identity.singleUseToken(v0.6.0) — issuer-supplied context after a single-use token is consumed
(v1.1.0) Identity-scoped middleware (caching, idempotency, rate limiting) resolves the caller through BetterRoute\Support\RequestIdentity: the auth attribute first, then a userId attribute, then the native WordPress user (get_current_user_id()), then the HMAC key id. A logged-in WP user is therefore scoped correctly even when no auth middleware is attached to the route.
Important policy note
Even with auth middleware, route registration still requires explicit permission_callback (by design in dispatcher integration). For middleware-authenticated routes, declare the intent with ->protectedByMiddleware(...) (since 0.4.0). For routes guarded by HMAC or single-use tokens (no WordPress user behind them), use ->publicRoute() and let the middleware be the gate.
(v1.1.0) This now applies to every HTTP method: raw Router routes — GET and OPTIONS included — deny by default until you declare intent with ->permission(), ->protectedByMiddleware(), or ->publicRoute(). See Router.
v1.1.0 hardening
- All raw routes deny by default.
GET/OPTIONSare no longer public without explicit intent (see the policy note above). - JWT lifetime cap requires
iat+exp. WithmaxLifetimeSecondsconfigured, tokens missing either claim are rejected instead of skipping the check. See JWT and Bearer. - JWKS refresh throttling. Unknown-
kidrefreshes respect per-verifier and persisted provider cooldowns, run under a MySQL advisory lock, and keep the last known-good keys when a fetch fails. See JWKS (RS256 / ES256). - Shared identity resolution.
RequestIdentityscopes cache/idempotency/rate-limit keys by auth identity, native WP user, or HMAC key id (see Context propagation above).
v1.0.0 hardening
WpClaimsUserMapperemail/login mapping is off by default. Only id claims and an explicit custom resolver map a WP user out of the box; email mapping is opt-in and requires a truthyemail_verifiedclaim. Prevents account takeover from unverified third-party-issuer email claims. See JWT and Bearer.- Granted-scope wildcards are opt-in. A trailing
*on a token-supplied scope is treated as a literal unlessallowGrantedScopeWildcards: true; server-defined required-scope wildcards are unchanged. - Optional HMAC query-string signing via
signQueryString(off by default). See HMAC Request Signatures. HttpJwksProvideruseswp_safe_remote_getwith bounded redirects and response size.
v0.6.0 additions
- Asymmetric JWT.
Rs256JwksJwtVerifierplusHttpJwksProviderandStaticJwksProviderfor OIDC-style providers. Strictkidmatching, algorithm pinning, private-field stripping. See JWKS (RS256 / ES256). - HMAC request signatures.
HmacSignatureMiddlewareplusHmacSecretProviderInterfaceandArrayHmacSecretProvider. Canonical input, replay window, multi-key rotation. See HMAC Request Signatures. - Single-use tokens.
SingleUseTokenMiddlewareplus three stores. See Single-Use Tokens.
v0.5.0 additions
OwnershipGuardMiddlewarefor routes where the authenticated user may only access their own object. DefaultdeniedStatusis404to avoid leaking existence.Resource\OwnedResourcePolicy::currentUserOwns()— Resource DSL preset that wires the URLid, the auth identity, and an optionalbypassCapabilitytogether. See Ownership guards.
v0.3.0 hardening
Hs256JwtVerifierrequiresexpby default and supportsexpectedIssuer,expectedAudience,maxLifetimeSeconds, andmaxTokenLength. See JWT and Bearer.WpClaimsUserMapperremoved'sub'from defaultidClaims— re-add it explicitly when needed.BearerTokenAuthMiddlewareno longer leaks the verifier exception message; failed tokens uniformly return401 invalid_tokenwith nodetails.reason.
Common mistakes
- Relying on middleware alone without route permissions
- Missing
Authorizationheader normalization - Not mapping JWT/Bearer claims to WP user where needed
Validation checklist
401on missing/invalid credential403on missing required scopes- expected auth attributes exist in
RequestContext