diff --git a/.changeset/bearer-tokens-in-guards.md b/.changeset/bearer-tokens-in-guards.md deleted file mode 100644 index 76e067a..0000000 --- a/.changeset/bearer-tokens-in-guards.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -'@seamless-auth/core': minor -'@seamless-auth/express': minor -'@seamless-auth/fastify': minor ---- - -Accept the auth API's access token as a bearer credential in `requireAuth` and `getSeamlessUser`. - -Both guards read `req.cookies` and nothing else, so a native client, which has no cookie jar -and holds the auth API's own tokens, was rejected on every request to an adopter's routes. -`requireAuth` now takes an optional `authServerUrl` + `audience` pair; with both configured it -also accepts `Authorization: Bearer `, verified against the auth API's JWKS -(issuer, audience, expiry) and required to carry `typ: "access"`, so a sign-in flow's -ephemeral token is refused even though the same key signs it. The cookie wins when both are -present, and leaving the pair out keeps the guard cookie-only, which is what every earlier -version did. Half of the pair is a setup error. - -`getSeamlessUser` resolves a bearer session too. The router options already carry -`authServerUrl` and `audience`, so no new option is needed there: a request with no access -cookie but a valid bearer token is verified the same way and forwarded to `GET /users/me` as -the caller's identity, while a request with neither, or a token that fails verification, -returns `null` without an upstream call. - -On the bearer path `req.user.email` and `req.user.phone` are unset, because the access token -does not carry them; `getSeamlessUser` hydrates the profile. - -Core exports `verifyAccessToken`, `extractBearerToken`, `authenticateBearer`, and -`authenticateRequest`. `getSeamlessUser` in core takes an optional `bearer: { authorization, -audience }`. The JWKS memo that `verifySignedAuthResponse` used moves to a shared module so both -verifiers share one instance per auth server. Fastify gains direct tests for its guards, which -until now were covered only through the plugin parity suite. - -Tracks fells-code/seamless-auth-server#147. diff --git a/.changeset/bearer-transport-mode.md b/.changeset/bearer-transport-mode.md deleted file mode 100644 index 5e8f2a6..0000000 --- a/.changeset/bearer-transport-mode.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -'@seamless-auth/core': minor -'@seamless-auth/express': minor -'@seamless-auth/fastify': minor ---- - -Serve a bearer transport on the auth routes for native clients, and add `POST /refresh`. - -Every proxied route assumed cookies: identity came from the cookie payload, session responses -were stripped of their tokens and minted into cookies, and silent refresh ran on the refresh -cookie. A native app has no cookie jar, so it could not sign in through the adapter at all, and -going around it to the auth API directly would bypass message delivery, client IP forwarding, -and the service token, and need the auth API exposed. - -A request that carries `x-seamless-auth-transport: bearer` now gets a bearer contract on the -same routes. The client presents the token a route needs in `Authorization: Bearer` (the -ephemeral token `/login` or `/registration/register` returned on pre-auth routes, the access -token on access routes) and the adapter forwards it to the auth API as-is. Session-issuing -responses come back whole, `token` and `refreshToken` included, with no `Set-Cookie`; the auth -API's signature on the access token is still verified before the body goes out. `ensureCookies` -is skipped. A route that needs an identity and gets no bearer token answers 401 with the same -error it gives a missing cookie. The header rather than the presence of `Authorization` selects -the transport, because the first request of a flow carries no token in either. Requests without -the header are served exactly as before. - -`POST /refresh` is new in both adapters. In bearer transport it takes `Authorization: Bearer -` and returns the rotated pair, passing the auth API's failure body through so a -client can tell `refresh_token_reused` from a transient error. Concurrent rotations of the same -token are collapsed into one upstream call, since the auth API treats a replayed refresh token as -theft. In cookie transport it rotates the refresh cookie into fresh session cookies, for a client -that wants an explicit refresh. - -Core: `AuthTransport`, `resolveAuthTransport`, `AUTH_TRANSPORT_HEADER`, `sessionResult` (what -every session-issuing handler now returns through), a `transport` option on `loginHandler`, -`registerHandler`, `finishLoginHandler`, the OTP verify handlers, -`pollMagicLinkConfirmationHandler`, `switchOrganizationHandler` and `finishOAuthLoginHandler`, -`transport` and `authorization` on `checkProxyIdentity`, `transport` on `applyResult`, -`refreshBearerSession`, and `refreshHandler`. The parity suite drives a full bearer sign-in -through both adapters. - -Closes fells-code/seamless-auth-server#163. diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 672f2ca..89c8861 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,73 @@ # @seamless-auth/core +## 0.16.0 + +### Minor Changes + +- 36d530b: Accept the auth API's access token as a bearer credential in `requireAuth` and `getSeamlessUser`. + + Both guards read `req.cookies` and nothing else, so a native client, which has no cookie jar + and holds the auth API's own tokens, was rejected on every request to an adopter's routes. + `requireAuth` now takes an optional `authServerUrl` + `audience` pair; with both configured it + also accepts `Authorization: Bearer `, verified against the auth API's JWKS + (issuer, audience, expiry) and required to carry `typ: "access"`, so a sign-in flow's + ephemeral token is refused even though the same key signs it. The cookie wins when both are + present, and leaving the pair out keeps the guard cookie-only, which is what every earlier + version did. Half of the pair is a setup error. + + `getSeamlessUser` resolves a bearer session too. The router options already carry + `authServerUrl` and `audience`, so no new option is needed there: a request with no access + cookie but a valid bearer token is verified the same way and forwarded to `GET /users/me` as + the caller's identity, while a request with neither, or a token that fails verification, + returns `null` without an upstream call. + + On the bearer path `req.user.email` and `req.user.phone` are unset, because the access token + does not carry them; `getSeamlessUser` hydrates the profile. + + Core exports `verifyAccessToken`, `extractBearerToken`, `authenticateBearer`, and + `authenticateRequest`. `getSeamlessUser` in core takes an optional `bearer: { authorization, +audience }`. The JWKS memo that `verifySignedAuthResponse` used moves to a shared module so both + verifiers share one instance per auth server. Fastify gains direct tests for its guards, which + until now were covered only through the plugin parity suite. + + Tracks fells-code/seamless-auth-server#147. + +- 0222376: Serve a bearer transport on the auth routes for native clients, and add `POST /refresh`. + + Every proxied route assumed cookies: identity came from the cookie payload, session responses + were stripped of their tokens and minted into cookies, and silent refresh ran on the refresh + cookie. A native app has no cookie jar, so it could not sign in through the adapter at all, and + going around it to the auth API directly would bypass message delivery, client IP forwarding, + and the service token, and need the auth API exposed. + + A request that carries `x-seamless-auth-transport: bearer` now gets a bearer contract on the + same routes. The client presents the token a route needs in `Authorization: Bearer` (the + ephemeral token `/login` or `/registration/register` returned on pre-auth routes, the access + token on access routes) and the adapter forwards it to the auth API as-is. Session-issuing + responses come back whole, `token` and `refreshToken` included, with no `Set-Cookie`; the auth + API's signature on the access token is still verified before the body goes out. `ensureCookies` + is skipped. A route that needs an identity and gets no bearer token answers 401 with the same + error it gives a missing cookie. The header rather than the presence of `Authorization` selects + the transport, because the first request of a flow carries no token in either. Requests without + the header are served exactly as before. + + `POST /refresh` is new in both adapters. In bearer transport it takes `Authorization: Bearer +` and returns the rotated pair, passing the auth API's failure body through so a + client can tell `refresh_token_reused` from a transient error. Concurrent rotations of the same + token are collapsed into one upstream call, since the auth API treats a replayed refresh token as + theft. In cookie transport it rotates the refresh cookie into fresh session cookies, for a client + that wants an explicit refresh. + + Core: `AuthTransport`, `resolveAuthTransport`, `AUTH_TRANSPORT_HEADER`, `sessionResult` (what + every session-issuing handler now returns through), a `transport` option on `loginHandler`, + `registerHandler`, `finishLoginHandler`, the OTP verify handlers, + `pollMagicLinkConfirmationHandler`, `switchOrganizationHandler` and `finishOAuthLoginHandler`, + `transport` and `authorization` on `checkProxyIdentity`, `transport` on `applyResult`, + `refreshBearerSession`, and `refreshHandler`. The parity suite drives a full bearer sign-in + through both adapters. + + Closes fells-code/seamless-auth-server#163. + ## 0.15.0 ### Minor Changes diff --git a/packages/core/package.json b/packages/core/package.json index a50fc16..569ad1b 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@seamless-auth/core", - "version": "0.15.0", + "version": "0.16.0", "description": "Framework-agnostic core authentication logic for SeamlessAuth", "keywords": [ "authentication", diff --git a/packages/express/CHANGELOG.md b/packages/express/CHANGELOG.md index 1bec3bf..ef6d8f7 100644 --- a/packages/express/CHANGELOG.md +++ b/packages/express/CHANGELOG.md @@ -1,5 +1,79 @@ # @seamless-auth/express +## 0.16.0 + +### Minor Changes + +- 36d530b: Accept the auth API's access token as a bearer credential in `requireAuth` and `getSeamlessUser`. + + Both guards read `req.cookies` and nothing else, so a native client, which has no cookie jar + and holds the auth API's own tokens, was rejected on every request to an adopter's routes. + `requireAuth` now takes an optional `authServerUrl` + `audience` pair; with both configured it + also accepts `Authorization: Bearer `, verified against the auth API's JWKS + (issuer, audience, expiry) and required to carry `typ: "access"`, so a sign-in flow's + ephemeral token is refused even though the same key signs it. The cookie wins when both are + present, and leaving the pair out keeps the guard cookie-only, which is what every earlier + version did. Half of the pair is a setup error. + + `getSeamlessUser` resolves a bearer session too. The router options already carry + `authServerUrl` and `audience`, so no new option is needed there: a request with no access + cookie but a valid bearer token is verified the same way and forwarded to `GET /users/me` as + the caller's identity, while a request with neither, or a token that fails verification, + returns `null` without an upstream call. + + On the bearer path `req.user.email` and `req.user.phone` are unset, because the access token + does not carry them; `getSeamlessUser` hydrates the profile. + + Core exports `verifyAccessToken`, `extractBearerToken`, `authenticateBearer`, and + `authenticateRequest`. `getSeamlessUser` in core takes an optional `bearer: { authorization, +audience }`. The JWKS memo that `verifySignedAuthResponse` used moves to a shared module so both + verifiers share one instance per auth server. Fastify gains direct tests for its guards, which + until now were covered only through the plugin parity suite. + + Tracks fells-code/seamless-auth-server#147. + +- 0222376: Serve a bearer transport on the auth routes for native clients, and add `POST /refresh`. + + Every proxied route assumed cookies: identity came from the cookie payload, session responses + were stripped of their tokens and minted into cookies, and silent refresh ran on the refresh + cookie. A native app has no cookie jar, so it could not sign in through the adapter at all, and + going around it to the auth API directly would bypass message delivery, client IP forwarding, + and the service token, and need the auth API exposed. + + A request that carries `x-seamless-auth-transport: bearer` now gets a bearer contract on the + same routes. The client presents the token a route needs in `Authorization: Bearer` (the + ephemeral token `/login` or `/registration/register` returned on pre-auth routes, the access + token on access routes) and the adapter forwards it to the auth API as-is. Session-issuing + responses come back whole, `token` and `refreshToken` included, with no `Set-Cookie`; the auth + API's signature on the access token is still verified before the body goes out. `ensureCookies` + is skipped. A route that needs an identity and gets no bearer token answers 401 with the same + error it gives a missing cookie. The header rather than the presence of `Authorization` selects + the transport, because the first request of a flow carries no token in either. Requests without + the header are served exactly as before. + + `POST /refresh` is new in both adapters. In bearer transport it takes `Authorization: Bearer +` and returns the rotated pair, passing the auth API's failure body through so a + client can tell `refresh_token_reused` from a transient error. Concurrent rotations of the same + token are collapsed into one upstream call, since the auth API treats a replayed refresh token as + theft. In cookie transport it rotates the refresh cookie into fresh session cookies, for a client + that wants an explicit refresh. + + Core: `AuthTransport`, `resolveAuthTransport`, `AUTH_TRANSPORT_HEADER`, `sessionResult` (what + every session-issuing handler now returns through), a `transport` option on `loginHandler`, + `registerHandler`, `finishLoginHandler`, the OTP verify handlers, + `pollMagicLinkConfirmationHandler`, `switchOrganizationHandler` and `finishOAuthLoginHandler`, + `transport` and `authorization` on `checkProxyIdentity`, `transport` on `applyResult`, + `refreshBearerSession`, and `refreshHandler`. The parity suite drives a full bearer sign-in + through both adapters. + + Closes fells-code/seamless-auth-server#163. + +### Patch Changes + +- Updated dependencies [36d530b] +- Updated dependencies [0222376] + - @seamless-auth/core@0.16.0 + ## 0.15.0 ### Minor Changes diff --git a/packages/express/package.json b/packages/express/package.json index ba727f7..2fc6db4 100644 --- a/packages/express/package.json +++ b/packages/express/package.json @@ -1,6 +1,6 @@ { "name": "@seamless-auth/express", - "version": "0.15.0", + "version": "0.16.0", "description": "Express adapter for Seamless Auth passwordless authentication", "keywords": [ "authentication", diff --git a/packages/fastify/CHANGELOG.md b/packages/fastify/CHANGELOG.md index e93ff53..11e3bed 100644 --- a/packages/fastify/CHANGELOG.md +++ b/packages/fastify/CHANGELOG.md @@ -1,5 +1,79 @@ # @seamless-auth/fastify +## 0.7.0 + +### Minor Changes + +- 36d530b: Accept the auth API's access token as a bearer credential in `requireAuth` and `getSeamlessUser`. + + Both guards read `req.cookies` and nothing else, so a native client, which has no cookie jar + and holds the auth API's own tokens, was rejected on every request to an adopter's routes. + `requireAuth` now takes an optional `authServerUrl` + `audience` pair; with both configured it + also accepts `Authorization: Bearer `, verified against the auth API's JWKS + (issuer, audience, expiry) and required to carry `typ: "access"`, so a sign-in flow's + ephemeral token is refused even though the same key signs it. The cookie wins when both are + present, and leaving the pair out keeps the guard cookie-only, which is what every earlier + version did. Half of the pair is a setup error. + + `getSeamlessUser` resolves a bearer session too. The router options already carry + `authServerUrl` and `audience`, so no new option is needed there: a request with no access + cookie but a valid bearer token is verified the same way and forwarded to `GET /users/me` as + the caller's identity, while a request with neither, or a token that fails verification, + returns `null` without an upstream call. + + On the bearer path `req.user.email` and `req.user.phone` are unset, because the access token + does not carry them; `getSeamlessUser` hydrates the profile. + + Core exports `verifyAccessToken`, `extractBearerToken`, `authenticateBearer`, and + `authenticateRequest`. `getSeamlessUser` in core takes an optional `bearer: { authorization, +audience }`. The JWKS memo that `verifySignedAuthResponse` used moves to a shared module so both + verifiers share one instance per auth server. Fastify gains direct tests for its guards, which + until now were covered only through the plugin parity suite. + + Tracks fells-code/seamless-auth-server#147. + +- 0222376: Serve a bearer transport on the auth routes for native clients, and add `POST /refresh`. + + Every proxied route assumed cookies: identity came from the cookie payload, session responses + were stripped of their tokens and minted into cookies, and silent refresh ran on the refresh + cookie. A native app has no cookie jar, so it could not sign in through the adapter at all, and + going around it to the auth API directly would bypass message delivery, client IP forwarding, + and the service token, and need the auth API exposed. + + A request that carries `x-seamless-auth-transport: bearer` now gets a bearer contract on the + same routes. The client presents the token a route needs in `Authorization: Bearer` (the + ephemeral token `/login` or `/registration/register` returned on pre-auth routes, the access + token on access routes) and the adapter forwards it to the auth API as-is. Session-issuing + responses come back whole, `token` and `refreshToken` included, with no `Set-Cookie`; the auth + API's signature on the access token is still verified before the body goes out. `ensureCookies` + is skipped. A route that needs an identity and gets no bearer token answers 401 with the same + error it gives a missing cookie. The header rather than the presence of `Authorization` selects + the transport, because the first request of a flow carries no token in either. Requests without + the header are served exactly as before. + + `POST /refresh` is new in both adapters. In bearer transport it takes `Authorization: Bearer +` and returns the rotated pair, passing the auth API's failure body through so a + client can tell `refresh_token_reused` from a transient error. Concurrent rotations of the same + token are collapsed into one upstream call, since the auth API treats a replayed refresh token as + theft. In cookie transport it rotates the refresh cookie into fresh session cookies, for a client + that wants an explicit refresh. + + Core: `AuthTransport`, `resolveAuthTransport`, `AUTH_TRANSPORT_HEADER`, `sessionResult` (what + every session-issuing handler now returns through), a `transport` option on `loginHandler`, + `registerHandler`, `finishLoginHandler`, the OTP verify handlers, + `pollMagicLinkConfirmationHandler`, `switchOrganizationHandler` and `finishOAuthLoginHandler`, + `transport` and `authorization` on `checkProxyIdentity`, `transport` on `applyResult`, + `refreshBearerSession`, and `refreshHandler`. The parity suite drives a full bearer sign-in + through both adapters. + + Closes fells-code/seamless-auth-server#163. + +### Patch Changes + +- Updated dependencies [36d530b] +- Updated dependencies [0222376] + - @seamless-auth/core@0.16.0 + ## 0.6.0 ### Minor Changes diff --git a/packages/fastify/package.json b/packages/fastify/package.json index 2ed6113..6f1c8cc 100644 --- a/packages/fastify/package.json +++ b/packages/fastify/package.json @@ -1,6 +1,6 @@ { "name": "@seamless-auth/fastify", - "version": "0.6.0", + "version": "0.7.0", "description": "Fastify adapter for Seamless Auth passwordless authentication", "keywords": [ "authentication",