Repository navigation
feat(nextjs): requireAuth and requireRole guards, trustedProxies client IP, adapter conformance - #266
Merged
Merged
Conversation
…nt IP Add requireAuth(handler, options) and requireRole(roles, handler, options) for App Router route handlers. They take the access cookie or a bearer access token, verify the token against the auth API's JWKS, refuse recovery sessions unless allowed, apply the origin check to cookie requests and never refresh. Refusals use the codes the Go, Python and Rust adapters answer with (unauthenticated, enrollment_required, cross_site_request_blocked, insufficient_role) and never echo roles. The user carries organizationId from the verified token's org_id, which core's authenticateBearer and authenticateRequest now set. Add a trustedProxies option that walks X-Forwarded-For from the right past the listed addresses or ranges, used when resolveClientIp is not given. There is no hop count option: a count cannot tell a proxy from a client. With neither set nothing is forwarded, and the handler logs one startup warning. getSeamlessSession resolves and forwards the client IP from the request headers too. Refs #262
…ence app conformance/nextjs-refapp is a private workspace app built on @seamless-auth/nextjs with the routes verify/CONFORMANCE.md in seamless-cli asks for: the adapter at /auth, /api/me behind requireAuth, and the /__captured delivery hook. A new job in conformance.yml builds it, starts it on the host and runs seamless verify --adapter-url against it, the way the Go, Python and Rust adapters run the same specs. It needs no seamless-cli change. Closes #262
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #262.
What
@seamless-auth/nextjsroute guardsrequireAuth(handler, opts)andrequireRole(roles, handler, opts)wrap App Router route handlers. The handler gets(request, context, user), ascreateResourceServer().protectdoes.opts(SeamlessGuardOptions) is a subset of the handler options, so one object serves both.Authorization: Bearer <access token>(the cookie wins when both are sent), verify the token against the auth API's key set so roles come from a signed token, apply the origin check to cookie requests, refuse recovery sessions unlessallowRecoverySessionis set, and never refresh.401 {"error":"unauthenticated"},403 enrollment_required,403 cross_site_request_blocked,403 insufficient_role. No body names any roles.requireRolematches withhasScopedRole(any listed role) and throws at setup on no role or a blank one.organizationIdfrom the verified token'sorg_id.Client IP
trustedProxies: string[](addresses or CIDR ranges) walksX-Forwarded-Forfrom the right past trusted hops, used whenresolveClientIpis not given. There is deliberately no hop-count option: a hop count cannot tell a proxy from a client, which is why the Go, Python and Rust adapters take a proxy list too. Invalid entries throw at setup.getSeamlessSessiontakes the requestheaderswithtrustedProxiesorresolveClientIp, forwards the client IP, and reads the user agent fromheaderswhenuserAgentis not given.Core
authenticateBearer, andauthenticateRequestwith bearer verification on, setorganizationIdfrom the verified token'sorg_id(newGuardUsertype). Express and Fastifyreq.usergain the field; their response bodies are unchanged here (that is refactor: serve passthrough routes from the manifest and align guard and 404 responses #263).Conformance
conformance/nextjs-refapp, a private workspace package, implements the reference app contract in seamless-cliverify/CONFORMANCE.md.nextjsjob inconformance.ymlstarts it and runsseamless verify --adapter-urlagainst it (seamless-cli at the same pinned SHA as the existing jobs), the way the Go, Python and Rust adapters run the specs. No seamless-cli change is needed.The same role guard semantics, refusal bodies and organization field are landing in the Go, Python and Rust adapters (seamless-auth-go#28, seamless-auth-python#31, seamless-auth-rust#32).
Changeset: minor for
@seamless-auth/nextjsand@seamless-auth/core. The linked versioning makes express minor and fastify patch.Checks
pnpm build: all packages done.pnpm test: core 598 passed, express 264 passed, nextjs 311 passed (includes the consumer type checks), fastify 271 passed. Parity tests add 28 cases running the Next.js guards against ExpressrequireAuthandrequireRole.pnpm check:types-current:@seamless-auth/types ^0.34.0is current.