$npx -y skills add Lonsdale201/wp-agent-skills --skill br-auth-middlewareConfigure Better Route 1.1 authentication with JWT, custom bearer tokens, WordPress Application Passwords, or cookie nonces. Use when protecting routes, mapping verified claims to WordPress users, enforcing scopes, or consuming the shared AuthContext identity.
| 1 | # Better Route authentication middleware |
| 2 | |
| 3 | Select authentication by client type, attach it as middleware, and mark every raw route as middleware-protected. Better Route 1.1 denies every raw route by default, including `GET` and `OPTIONS`. |
| 4 | |
| 5 | ```php |
| 6 | use BetterRoute\Middleware\Jwt\Hs256JwtVerifier; |
| 7 | use BetterRoute\Middleware\Jwt\JwtAuthMiddleware; |
| 8 | |
| 9 | $auth = new JwtAuthMiddleware( |
| 10 | verifier: new Hs256JwtVerifier( |
| 11 | secret: MY_PLUGIN_JWT_SECRET, |
| 12 | expectedIssuer: 'https://issuer.example', |
| 13 | expectedAudience: 'my-api', |
| 14 | maxLifetimeSeconds: 3600 |
| 15 | ), |
| 16 | requiredScopes: ['orders:read'] |
| 17 | ); |
| 18 | |
| 19 | $router->get('/orders/(?P<id>\d+)', $handler) |
| 20 | ->middleware([$auth]) |
| 21 | ->protectedByMiddleware('bearerAuth'); |
| 22 | ``` |
| 23 | |
| 24 | ## Choose the middleware |
| 25 | |
| 26 | - Use `JwtAuthMiddleware` with `Hs256JwtVerifier` for first-party HS256 tokens. |
| 27 | - Use `BearerTokenAuthMiddleware` with `JwtBearerTokenVerifierAdapter` and `Rs256JwksJwtVerifier` for RS256/ES256 JWKS tokens. Follow `br-jwks-jwt-auth`. |
| 28 | - Use `BearerTokenAuthMiddleware` with a custom `BearerTokenVerifierInterface` for opaque or externally verified bearer tokens. |
| 29 | - Use `ApplicationPasswordAuthMiddleware` for server-to-server WordPress Application Password Basic authentication. |
| 30 | - Use `CookieNonceAuthMiddleware` for same-site browser requests with a logged-in WordPress cookie and `X-WP-Nonce`. Keep both `requireNonce` and `requireLoggedIn` enabled unless a separately reviewed design requires otherwise. |
| 31 | |
| 32 | `protectedByMiddleware()` tells the WordPress permission callback to let the request reach the middleware pipeline. It does not add authentication by itself: the authentication middleware must also be attached. The optional name describes the OpenAPI security scheme. |
| 33 | |
| 34 | ## JWT verification rules |
| 35 | |
| 36 | - `exp` is required by default. Do not disable `requireExpiration` for normal production tokens. |
| 37 | - When `maxLifetimeSeconds` is set, both `iat` and `exp` are required and `exp - iat` must not exceed the limit. |
| 38 | - Set `expectedIssuer` and `expectedAudience` in production. |
| 39 | - Keep `maxTokenLength` bounded; the default is 8192 bytes. |
| 40 | - Required-scope wildcards are server-controlled. A token-supplied granted scope ending in `*` expands authority only when `allowGrantedScopeWildcards: true`; keep that opt-in off unless the issuer contract requires it. |
| 41 | |
| 42 | ## WordPress user mapping |
| 43 | |
| 44 | `WpClaimsUserMapper` defaults to numeric `user_id`, `uid`, and `wp_user_id` claims. It deliberately does not interpret `sub` as a WordPress user ID and leaves email/login lookup disabled. |
| 45 | |
| 46 | Prefer an issuer-scoped custom `sub` resolver. If email mapping is unavoidable, explicitly pass `emailClaims` and retain `requireEmailVerified: true`. Enable login-name mapping only for a fully controlled issuer. A mapped positive user ID also becomes the native WordPress current user. |
| 47 | |
| 48 | ## Shared identity |
| 49 | |
| 50 | Successful built-in authentication writes a normalized identity into `RequestContext::$attributes['auth']` with `provider`, `userId`, `subject`, and `scopes`. JWT/bearer claims and useful user fields are exposed through other context attributes. Ownership guards, rate-limit identity selection, and audit enrichment consume this shared contract; do not invent a parallel identity attribute. |
| 51 | |
| 52 | ## Checks |
| 53 | |
| 54 | - Test missing, malformed, expired, future, wrong-issuer, wrong-audience, and over-lifetime tokens. |
| 55 | - Test every missing required scope and ensure a token-provided wildcard cannot widen authority unexpectedly. |
| 56 | - Test routes without `protectedByMiddleware()` fail closed. |
| 57 | - Never log bearer tokens, Basic credentials, cookies, nonces, or complete claims payloads. |
| 58 | |
| 59 | Source references: `src/Middleware/Jwt/*`, `src/Middleware/Auth/*`, `src/Router/RouteBuilder.php`. |
| 60 | |
| 61 | ## References |
| 62 | |
| 63 | - Official documentation: <https://lonsdale201.github.io/better-docs/docs/better-route/agents> |