@atlasauth/nextjs 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,45 @@
1
+ # @atlasauth/nextjs changelog
2
+
3
+ ## 0.2.0
4
+
5
+ ### Added
6
+ - **Next.js 16 `proxy.ts` support.** `atlasProxy(options)` returns `(request) => Promise<Response | null>`. It resolves to a `Response` when Atlas must act (the sign-in redirect, the cross-property handshake, or a JSON 401 for `/api/*`) and to `null` to let the rest of the proxy run. It takes the same options and makes the same decisions as `atlasMiddleware`. It uses only Web-standard APIs, so it runs on both the Node.js runtime (the Next 16 default) and the Edge runtime.
7
+ - `withAtlasHeaders(request, response, auth?)` forwards the verified session to the app as request headers: `x-atlas-auth-status`, `x-atlas-user-id`, `x-atlas-session-id`, `x-atlas-org-id` and `x-atlas-org-role`. It works on a `NextResponse.next()` or a rewrite produced by any later step, such as next-intl, and merges with request-header overrides already set. It always drops `x-atlas-*` headers sent by the client.
8
+ - `readAtlasHeaders(headers)` returns the forwarded session as a `ForwardedAuth` (`{ signedIn, userId, sessionId, orgId, orgRole }`). `proxyAuth(request)` returns the `AuthState` the proxy resolved for a request. `ATLAS_AUTH_HEADERS` names the header constants.
9
+ - New types: `AtlasProxy`, `ProxyRequest`, `HeaderCarryingResponse`, `ForwardedAuth`.
10
+ - **Locale-prefixed routes.** Route patterns accept whole-segment `:name` parameters (`/:locale/dashboard(.*)`). The new `MiddlewareConfig` fields `locales` and `defaultLocale` restrict a `:locale` segment to the listed locales and fill in a `signInUrl` such as `/:locale/sign-in` from the request. New exports: `localizeSignInUrl` and the `PatternOptions` type. `matchesPattern`, `matchesAny` and `createRouteMatcher` take an optional `PatternOptions` argument.
11
+ - `createAtlasDecider(options)` exposes the runtime-neutral decision engine behind both `atlasMiddleware` and `atlasProxy`. It resolves to an `AtlasDecision` (`continue`, `redirect` with cookies, or `unauthorized`). New types: `AtlasDecision`, `AtlasCookie`. New constant: `UNAUTHENTICATED_BODY`.
12
+ - A package README.
13
+
14
+ ### Changed
15
+ - `atlasMiddleware` / `authMiddleware` now render the shared decision engine. Their behaviour and signature are unchanged.
16
+ - Patterns without a `:name` segment keep their exact previous meaning.
17
+
18
+ ## 0.1.4
19
+
20
+ ### Added
21
+ - New `@atlasauth/nextjs/server` entry with pre-bound, zero-argument `auth()` and `currentUser()`. They read the ambient request through `next/headers` and their config from `ATLAS_JWKS_URL` / `ATLAS_ISSUER` (or the `NEXT_PUBLIC_` forms). The base entry still doesn't need `next` installed.
22
+ - `atlasClient()`: a configured `@atlasauth/backend` client built from `ATLAS_SECRET_KEY` (and `ATLAS_API_URL`, if set).
23
+ - `configFromEnv()`, `backendConfigFromEnv()`, `buildEdgeRequest()`, and the `ServerAuth`, `CookieStoreLike` and `HeaderStoreLike` types.
24
+
25
+ ## 0.1.3
26
+
27
+ ### Added
28
+ - `createRouteMatcher(patterns)`. It returns a predicate over a `NextRequest`, a `{ nextUrl }` / `{ url }` object, or a path string, using the same `(.*)` pattern engine as the middleware.
29
+
30
+ ## 0.1.2
31
+
32
+ ### Added
33
+ - The middleware honours the durable signed-in hint (`__atlas_uat`, or the same-origin `__atlas_rt` cookie). A signed-in user whose short-lived `__session` has lapsed between refreshes is let through instead of being redirected to sign-in. Exported as `hasSignedInHint(request)`.
34
+ - `authMiddleware`, an alias of `atlasMiddleware`.
35
+ - `createCurrentUserHelper(options)` returns `currentUser(request)`. It gives a `CurrentUser` (`id`, `orgId`, `orgRole`, `email`, `name`, `firstName`, `lastName`), read from the verified session claims without a network call.
36
+
37
+ ## 0.1.1
38
+
39
+ First release published under the `@atlasauth` scope.
40
+
41
+ ### Added
42
+ - `atlasMiddleware(options)`: verifies the session JWT locally (JWKS cached in-process), protects routes by default (`publicRoutes` / `protectedRoutes`, where protected wins), returns a 401 JSON response for `/api/*`, skips static assets, and validates `redirect_url` (`safeRedirect`).
43
+ - `createAuthHelper(options)` returns `auth(request)`, with `has(condition)` and `protect(condition)` over the full permission/role condition set shared with the other Atlas SDKs.
44
+ - Cross-property SSO: `handshake: true` (with `publishableKey`, and optionally `fapiOrigin`) bounces a signed-out visitor through the Atlas handshake once, PKCE-bound and loop-guarded. A cross-domain return redeems the nonce and sets first-party `__session` / `__atlas_rt` cookies.
45
+ - Exports: `resolveAuth`, `SIGNED_OUT`, `decideRoute`, `matchesPattern`, `matchesAny`, `isStaticAsset`, `DEFAULT_SIGN_IN_URL`, and the `AuthState`, `EdgeRequest`, `EdgeResponse`, `EdgeRedirect`, `EdgeCookies`, `MiddlewareConfig` and `RouteDecision` types.
package/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # @atlasauth/nextjs
2
+
3
+ Atlas authentication for Next.js (App Router). It covers route protection in `middleware.ts` (Next 14/15) or `proxy.ts` (Next 16), plus `auth()` and `currentUser()` in server components and route handlers. Session tokens are verified locally against your instance's JWKS, so a warm instance makes no network call.
4
+
5
+ ```bash
6
+ npm install @atlasauth/nextjs
7
+ ```
8
+
9
+ `next` is an optional peer dependency (`>=13.4`, including 16).
10
+
11
+ ## Next.js 16: `proxy.ts`
12
+
13
+ ```ts
14
+ // proxy.ts
15
+ import { NextResponse, type NextRequest } from 'next/server';
16
+ import { atlasProxy, withAtlasHeaders } from '@atlasauth/nextjs';
17
+
18
+ const atlas = atlasProxy({
19
+ jwksUrl: 'https://auth.example.com/.well-known/jwks.json',
20
+ issuer: 'https://auth.example.com',
21
+ publicRoutes: ['/', '/sign-in(.*)', '/sign-up(.*)'],
22
+ });
23
+
24
+ export async function proxy(request: NextRequest) {
25
+ return (await atlas(request)) ?? withAtlasHeaders(request, NextResponse.next());
26
+ }
27
+
28
+ export const config = { matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'] };
29
+ ```
30
+
31
+ - `atlas(request)` resolves to a `Response` when Atlas has to act (a sign-in redirect, the cross-property handshake, or a JSON 401 for `/api/*`). Otherwise it resolves to `null` and your proxy carries on.
32
+ - `withAtlasHeaders(request, response)` forwards the verified session to your app on whatever response the rest of your proxy returns, as `x-atlas-auth-status`, `x-atlas-user-id`, `x-atlas-session-id`, `x-atlas-org-id` and `x-atlas-org-role` request headers. It merges with request-header overrides that other steps have already set, and it always drops `x-atlas-*` headers sent by the client. Read them in a server component with `readAtlasHeaders(await headers())`.
33
+ - `proxyAuth(request)` returns the auth state the proxy already resolved, for extra checks inside `proxy.ts`.
34
+
35
+ **Why `Response | null`?** In Next 16 the proxy is usually a chain (auth, then i18n, then your own logic), so Atlas returns a response only when it must and otherwise steps aside. The session is attached to the final response with `withAtlasHeaders`, and the token is verified only once.
36
+
37
+ It uses only Web-standard APIs, so it runs on both the Node.js runtime (the Next 16 default) and the Edge runtime.
38
+
39
+ ### With next-intl
40
+
41
+ ```ts
42
+ import createMiddleware from 'next-intl/middleware';
43
+ import type { NextRequest } from 'next/server';
44
+ import { atlasProxy, withAtlasHeaders } from '@atlasauth/nextjs';
45
+ import { routing } from './i18n/routing';
46
+
47
+ const intl = createMiddleware(routing);
48
+ const atlas = atlasProxy({
49
+ jwksUrl: 'https://auth.example.com/.well-known/jwks.json',
50
+ issuer: 'https://auth.example.com',
51
+ locales: routing.locales,
52
+ defaultLocale: routing.defaultLocale,
53
+ publicRoutes: ['/', '/:locale', '/:locale/sign-in(.*)'],
54
+ protectedRoutes: ['/:locale/dashboard(.*)'],
55
+ signInUrl: '/:locale/sign-in', // /de/dashboard → /de/sign-in?redirect_url=…
56
+ });
57
+
58
+ export async function proxy(request: NextRequest) {
59
+ return (await atlas(request)) ?? withAtlasHeaders(request, intl(request));
60
+ }
61
+ ```
62
+
63
+ A `:locale` segment matches only the configured `locales`. Any other `:name` segment matches any single path segment.
64
+
65
+ ## Next.js 14/15: `middleware.ts`
66
+
67
+ ```ts
68
+ import { authMiddleware } from '@atlasauth/nextjs';
69
+ import { NextResponse, type NextRequest } from 'next/server';
70
+
71
+ const middleware = authMiddleware({
72
+ jwksUrl: 'https://auth.example.com/.well-known/jwks.json',
73
+ issuer: 'https://auth.example.com',
74
+ publicRoutes: ['/', '/sign-in(.*)'],
75
+ });
76
+
77
+ export default function (request: NextRequest) {
78
+ return middleware(request, NextResponse);
79
+ }
80
+ ```
81
+
82
+ `atlasMiddleware` is the same function as `authMiddleware`.
83
+
84
+ ## Server components and route handlers
85
+
86
+ ```ts
87
+ import { auth, currentUser } from '@atlasauth/nextjs/server';
88
+
89
+ const { userId, protect } = await auth();
90
+ const user = await currentUser(); // from the verified session claims, no network call
91
+ ```
92
+
93
+ These read `ATLAS_JWKS_URL` and `ATLAS_ISSUER` (or their `NEXT_PUBLIC_` forms) from the environment.
94
+
95
+ ## Routing rules
96
+
97
+ - Routes are protected unless they match `publicRoutes`. `protectedRoutes` wins over `publicRoutes`.
98
+ - Patterns support a trailing `(.*)` and whole-segment `:name` parameters. They aren't regular expressions.
99
+ - A signed-in user whose short-lived `__session` cookie has expired is let through on the durable signed-in hint, so the client can refresh it. It doesn't bounce to sign-in.
100
+
101
+ ## Changelog
102
+
103
+ See [CHANGELOG.md](./CHANGELOG.md).
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './matcher';
2
2
  export * from './middleware';
3
+ export * from './proxy';
package/dist/index.js CHANGED
@@ -16,4 +16,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./matcher"), exports);
18
18
  __exportStar(require("./middleware"), exports);
19
+ __exportStar(require("./proxy"), exports);
19
20
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,+CAA6B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,+CAA6B;AAC7B,0CAAwB"}
package/dist/matcher.d.ts CHANGED
@@ -12,15 +12,26 @@
12
12
  * which is a loud failure rather than a silent breach.
13
13
  */
14
14
  /**
15
- * Patterns support one wildcard form: `(.*)` at the end, matching Next.js's own
16
- * matcher syntax so a developer writes one dialect rather than two.
15
+ * Patterns support two forms, both from Next.js's own matcher dialect so a
16
+ * developer writes one dialect rather than two:
17
+ *
18
+ * - `(.*)` at the end — matches the rest of the path (`/admin(.*)`).
19
+ * - `:name` as a whole segment — matches exactly one non-empty segment
20
+ * (`/:locale/dashboard`). This is what makes locale-prefixed routing
21
+ * (next-intl and friends) expressible. When {@link PatternOptions.locales} is
22
+ * given, a `:locale` segment matches ONLY those values, so
23
+ * `/:locale/sign-in` can't make `/admin/sign-in` public by accident.
17
24
  *
18
25
  * Deliberately NOT a general regex. A customer-authored regex in an
19
26
  * authorization path is a catastrophic-backtracking outage waiting to happen,
20
27
  * and `/admin(.*)` covers what anyone actually needs.
21
28
  */
22
- export declare function matchesPattern(pathname: string, pattern: string): boolean;
23
- export declare function matchesAny(pathname: string, patterns: readonly string[]): boolean;
29
+ export interface PatternOptions {
30
+ /** The app's locales. Restricts what a `:locale` pattern segment matches. */
31
+ locales?: readonly string[];
32
+ }
33
+ export declare function matchesPattern(pathname: string, pattern: string, options?: PatternOptions): boolean;
34
+ export declare function matchesAny(pathname: string, patterns: readonly string[], options?: PatternOptions): boolean;
24
35
  /**
25
36
  * §10.1 Clerk-parity `createRouteMatcher(patterns)` — the idiom integrators write
26
37
  * at the top of `middleware.ts` (`const isProtected = createRouteMatcher(['/dashboard(.*)'])`).
@@ -30,7 +41,7 @@ export declare function matchesAny(pathname: string, patterns: readonly string[]
30
41
  * matcher written here and the middleware's own routing agree exactly (no second
31
42
  * dialect, no customer regex in the auth path).
32
43
  */
33
- export declare function createRouteMatcher(patterns: readonly string[]): (input: string | {
44
+ export declare function createRouteMatcher(patterns: readonly string[], options?: PatternOptions): (input: string | {
34
45
  nextUrl?: {
35
46
  pathname?: string;
36
47
  };
@@ -45,7 +56,23 @@ export interface MiddlewareConfig {
45
56
  signInUrl?: string;
46
57
  /** Exact origins a `redirect_url` may point at (§13.1). */
47
58
  allowedOrigins?: readonly string[];
59
+ /**
60
+ * The app's locales, for locale-prefixed routing (next-intl and similar). A
61
+ * `:locale` segment in `publicRoutes`/`protectedRoutes` then matches only
62
+ * these values, and a `signInUrl` containing `/:locale` is filled in from the
63
+ * request's own locale prefix.
64
+ */
65
+ locales?: readonly string[];
66
+ /** Locale used for a `/:locale` sign-in URL when the request carries none. When
67
+ * absent, the `/:locale` segment is dropped and the i18n layer picks one. */
68
+ defaultLocale?: string;
48
69
  }
70
+ /**
71
+ * Fill a `signInUrl` like `/:locale/sign-in` from the request path's locale
72
+ * prefix, so a signed-out visitor on `/de/dashboard` lands on `/de/sign-in`
73
+ * rather than bouncing through the i18n layer's own redirect.
74
+ */
75
+ export declare function localizeSignInUrl(signInUrl: string, pathname: string, config?: Pick<MiddlewareConfig, 'locales' | 'defaultLocale'>): string;
49
76
  export declare const DEFAULT_SIGN_IN_URL = "/sign-in";
50
77
  export type RouteDecision = {
51
78
  action: 'skip';
package/dist/matcher.js CHANGED
@@ -18,28 +18,51 @@ exports.matchesPattern = matchesPattern;
18
18
  exports.matchesAny = matchesAny;
19
19
  exports.createRouteMatcher = createRouteMatcher;
20
20
  exports.isStaticAsset = isStaticAsset;
21
+ exports.localizeSignInUrl = localizeSignInUrl;
21
22
  exports.decideRoute = decideRoute;
22
23
  exports.safeRedirect = safeRedirect;
23
- /**
24
- * Patterns support one wildcard form: `(.*)` at the end, matching Next.js's own
25
- * matcher syntax so a developer writes one dialect rather than two.
26
- *
27
- * Deliberately NOT a general regex. A customer-authored regex in an
28
- * authorization path is a catastrophic-backtracking outage waiting to happen,
29
- * and `/admin(.*)` covers what anyone actually needs.
30
- */
31
- function matchesPattern(pathname, pattern) {
24
+ function segmentMatches(actual, pattern, options) {
25
+ if (!pattern.startsWith(':'))
26
+ return actual === pattern;
27
+ if (actual === '')
28
+ return false;
29
+ if (pattern === ':locale' && options.locales)
30
+ return options.locales.includes(actual);
31
+ return true;
32
+ }
33
+ function matchesPattern(pathname, pattern, options = {}) {
32
34
  if (pattern === pathname)
33
35
  return true;
34
36
  const wildcard = pattern.indexOf('(.*)');
35
- if (wildcard === -1)
36
- return false;
37
37
  // Anything after the wildcard is meaningless — `(.*)` already matched it.
38
- const prefix = pattern.slice(0, wildcard);
39
- return pathname.startsWith(prefix);
38
+ const prefix = wildcard === -1 ? pattern : pattern.slice(0, wildcard);
39
+ // No `:param` segment: the original string semantics, unchanged.
40
+ if (!prefix.includes('/:')) {
41
+ return wildcard !== -1 && pathname.startsWith(prefix);
42
+ }
43
+ const want = prefix.split('/');
44
+ const have = pathname.split('/');
45
+ if (wildcard === -1) {
46
+ return (want.length === have.length &&
47
+ want.every((segment, i) => segmentMatches(have[i], segment, options)));
48
+ }
49
+ // Wildcard: every segment but the last matches whole; the last one keeps the
50
+ // string-prefix semantics (`/:locale/dash(.*)` matches `/en/dashboard`), and a
51
+ // trailing `:param` must still be present.
52
+ if (have.length < want.length)
53
+ return false;
54
+ const last = want.length - 1;
55
+ for (let i = 0; i < last; i++) {
56
+ if (!segmentMatches(have[i], want[i], options))
57
+ return false;
58
+ }
59
+ const tail = want[last];
60
+ return tail.startsWith(':')
61
+ ? segmentMatches(have[last], tail, options)
62
+ : have[last].startsWith(tail);
40
63
  }
41
- function matchesAny(pathname, patterns) {
42
- return patterns.some((pattern) => matchesPattern(pathname, pattern));
64
+ function matchesAny(pathname, patterns, options = {}) {
65
+ return patterns.some((pattern) => matchesPattern(pathname, pattern, options));
43
66
  }
44
67
  /**
45
68
  * §10.1 Clerk-parity `createRouteMatcher(patterns)` — the idiom integrators write
@@ -50,7 +73,7 @@ function matchesAny(pathname, patterns) {
50
73
  * matcher written here and the middleware's own routing agree exactly (no second
51
74
  * dialect, no customer regex in the auth path).
52
75
  */
53
- function createRouteMatcher(patterns) {
76
+ function createRouteMatcher(patterns, options = {}) {
54
77
  return (input) => {
55
78
  let pathname;
56
79
  if (typeof input === 'string') {
@@ -61,7 +84,7 @@ function createRouteMatcher(patterns) {
61
84
  pathname =
62
85
  input.nextUrl?.pathname ?? (input.url ? new URL(input.url, 'http://x').pathname : '');
63
86
  }
64
- return matchesAny(pathname, patterns);
87
+ return matchesAny(pathname, patterns, options);
65
88
  };
66
89
  }
67
90
  /**
@@ -79,6 +102,20 @@ function isStaticAsset(pathname) {
79
102
  const last = pathname.split('/').pop() ?? '';
80
103
  return last.includes('.');
81
104
  }
105
+ /**
106
+ * Fill a `signInUrl` like `/:locale/sign-in` from the request path's locale
107
+ * prefix, so a signed-out visitor on `/de/dashboard` lands on `/de/sign-in`
108
+ * rather than bouncing through the i18n layer's own redirect.
109
+ */
110
+ function localizeSignInUrl(signInUrl, pathname, config = {}) {
111
+ if (!signInUrl.includes('/:locale'))
112
+ return signInUrl;
113
+ const first = pathname.split('/')[1] ?? '';
114
+ const locale = config.locales?.includes(first) ? first : config.defaultLocale;
115
+ return locale
116
+ ? signInUrl.replace('/:locale', `/${locale}`)
117
+ : signInUrl.replace('/:locale', '') || '/';
118
+ }
82
119
  exports.DEFAULT_SIGN_IN_URL = '/sign-in';
83
120
  /**
84
121
  * Decide what to do with a request.
@@ -92,8 +129,9 @@ function decideRoute(input) {
92
129
  const config = input.config ?? {};
93
130
  if (isStaticAsset(input.pathname))
94
131
  return { action: 'skip' };
95
- const explicitlyProtected = matchesAny(input.pathname, config.protectedRoutes ?? []);
96
- const isPublic = !explicitlyProtected && matchesAny(input.pathname, config.publicRoutes ?? []);
132
+ const patternOptions = { locales: config.locales };
133
+ const explicitlyProtected = matchesAny(input.pathname, config.protectedRoutes ?? [], patternOptions);
134
+ const isPublic = !explicitlyProtected && matchesAny(input.pathname, config.publicRoutes ?? [], patternOptions);
97
135
  if (isPublic || input.signedIn)
98
136
  return { action: 'allow' };
99
137
  /**
@@ -103,7 +141,7 @@ function decideRoute(input) {
103
141
  */
104
142
  if (input.isApiRoute)
105
143
  return { action: 'unauthorized' };
106
- const signInUrl = config.signInUrl ?? exports.DEFAULT_SIGN_IN_URL;
144
+ const signInUrl = localizeSignInUrl(config.signInUrl ?? exports.DEFAULT_SIGN_IN_URL, input.pathname, config);
107
145
  return {
108
146
  action: 'redirect',
109
147
  to: `${signInUrl}?redirect_url=${encodeURIComponent(input.pathname)}`,
@@ -1 +1 @@
1
- {"version":3,"file":"matcher.js","sourceRoot":"","sources":["../src/matcher.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"matcher.js","sourceRoot":"","sources":["../src/matcher.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;AA6BH,wCAqCC;AAED,gCAMC;AAWD,gDAeC;AAWD,sCAKC;AA2BD,8CAWC;AAkBD,kCAkCC;AASD,oCAiBC;AAlND,SAAS,cAAc,CAAC,MAAc,EAAE,OAAe,EAAE,OAAuB;IAC9E,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,MAAM,KAAK,OAAO,CAAC;IACxD,IAAI,MAAM,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAChC,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,OAAO;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACtF,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAgB,cAAc,CAC5B,QAAgB,EAChB,OAAe,EACf,UAA0B,EAAE;IAE5B,IAAI,OAAO,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAEtC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,0EAA0E;IAC1E,MAAM,MAAM,GAAG,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAEtE,iEAAiE;IACjE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,OAAO,QAAQ,KAAK,CAAC,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACpB,OAAO,CACL,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;YAC3B,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAE,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CACvE,CAAC;IACJ,CAAC;IAED,6EAA6E;IAC7E,+EAA+E;IAC/E,2CAA2C;IAC3C,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAE,EAAE,IAAI,CAAC,CAAC,CAAE,EAAE,OAAO,CAAC;YAAE,OAAO,KAAK,CAAC;IACjE,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAE,CAAC;IACzB,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QACzB,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAE,EAAE,IAAI,EAAE,OAAO,CAAC;QAC5C,CAAC,CAAC,IAAI,CAAC,IAAI,CAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,SAAgB,UAAU,CACxB,QAAgB,EAChB,QAA2B,EAC3B,UAA0B,EAAE;IAE5B,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AAChF,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,kBAAkB,CAChC,QAA2B,EAC3B,UAA0B,EAAE;IAE5B,OAAO,CAAC,KAAK,EAAE,EAAE;QACf,IAAI,QAAgB,CAAC;QACrB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,oCAAoC;YACpC,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;QACxE,CAAC;aAAM,CAAC;YACN,QAAQ;gBACN,KAAK,CAAC,OAAO,EAAE,QAAQ,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC1F,CAAC;QACD,OAAO,UAAU,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,cAAc,GAAG,CAAC,SAAS,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,CAAC,CAAC;AAEnG,SAAgB,aAAa,CAAC,QAAgB;IAC5C,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9E,gDAAgD;IAChD,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;IAC7C,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAsBD;;;;GAIG;AACH,SAAgB,iBAAiB,CAC/B,SAAiB,EACjB,QAAgB,EAChB,SAA8D,EAAE;IAEhE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,SAAS,CAAC;IACtD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC;IAC9E,OAAO,MAAM;QACX,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,MAAM,EAAE,CAAC;QAC7C,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;AAC/C,CAAC;AAEY,QAAA,mBAAmB,GAAG,UAAU,CAAC;AAQ9C;;;;;;;GAOG;AACH,SAAgB,WAAW,CAAC,KAM3B;IACC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC;IAElC,IAAI,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAE7D,MAAM,cAAc,GAAmB,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IACnE,MAAM,mBAAmB,GAAG,UAAU,CACpC,KAAK,CAAC,QAAQ,EACd,MAAM,CAAC,eAAe,IAAI,EAAE,EAC5B,cAAc,CACf,CAAC;IACF,MAAM,QAAQ,GACZ,CAAC,mBAAmB,IAAI,UAAU,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,YAAY,IAAI,EAAE,EAAE,cAAc,CAAC,CAAC;IAEhG,IAAI,QAAQ,IAAI,KAAK,CAAC,QAAQ;QAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IAE3D;;;;OAIG;IACH,IAAI,KAAK,CAAC,UAAU;QAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;IAExD,MAAM,SAAS,GAAG,iBAAiB,CAAC,MAAM,CAAC,SAAS,IAAI,2BAAmB,EAAE,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACrG,OAAO;QACL,MAAM,EAAE,UAAU;QAClB,EAAE,EAAE,GAAG,SAAS,iBAAiB,kBAAkB,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE;KACtE,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,YAAY,CAC1B,WAAsC,EACtC,iBAAoC,EAAE,EACtC,QAAQ,GAAG,GAAG;IAEd,IAAI,CAAC,WAAW;QAAE,OAAO,QAAQ,CAAC;IAElC,yEAAyE;IACzE,IAAI,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAC;IAClD,IAAI,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,WAAW,CAAC;IAEpD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;QACjC,OAAO,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC;IACtE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -95,6 +95,48 @@ export declare function hasSignedInHint(request: EdgeRequest): boolean;
95
95
  * user needs anyway.
96
96
  */
97
97
  export declare function resolveAuth(backend: AtlasBackend, request: EdgeRequest): Promise<AuthState>;
98
+ /** A first-party cookie Atlas wants set on the response it returns. */
99
+ export interface AtlasCookie {
100
+ name: string;
101
+ value: string;
102
+ options: {
103
+ path?: string;
104
+ httpOnly?: boolean;
105
+ sameSite?: 'lax' | 'strict' | 'none';
106
+ secure?: boolean;
107
+ maxAge?: number;
108
+ };
109
+ }
110
+ /**
111
+ * What Atlas decided for one request, before it is rendered into any particular
112
+ * response type. `atlasMiddleware` renders it through Next's `NextResponse`
113
+ * helpers; `atlasProxy` renders it as a standard Web `Response`. Keeping the
114
+ * decision in one place means the two can never disagree about who is let in.
115
+ */
116
+ export type AtlasDecision = {
117
+ kind: 'continue';
118
+ auth: AuthState;
119
+ } | {
120
+ kind: 'redirect';
121
+ location: string;
122
+ cookies: AtlasCookie[];
123
+ auth: AuthState;
124
+ } | {
125
+ kind: 'unauthorized';
126
+ auth: AuthState;
127
+ };
128
+ /**
129
+ * The runtime-neutral decision engine behind {@link atlasMiddleware} and
130
+ * `atlasProxy`. Uses only Web-standard APIs (`URL`, `fetch`, Web Crypto), so it
131
+ * runs unchanged on the Edge runtime and on Node.
132
+ */
133
+ export declare function createAtlasDecider(options: AtlasMiddlewareOptions): (request: EdgeRequest) => Promise<AtlasDecision>;
134
+ /** The JSON body Atlas answers an unauthenticated API request with. */
135
+ export declare const UNAUTHENTICATED_BODY: {
136
+ readonly errors: readonly [{
137
+ readonly code: "UNAUTHENTICATED";
138
+ }];
139
+ };
98
140
  export declare function atlasMiddleware(options: AtlasMiddlewareOptions): (request: EdgeRequest, response: EdgeResponse) => Promise<unknown>;
99
141
  /**
100
142
  * The `auth()` helper for server components and route handlers.
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.safeRedirect = exports.authMiddleware = exports.SIGNED_OUT = void 0;
3
+ exports.safeRedirect = exports.authMiddleware = exports.UNAUTHENTICATED_BODY = exports.SIGNED_OUT = void 0;
4
4
  exports.hasSignedInHint = hasSignedInHint;
5
5
  exports.resolveAuth = resolveAuth;
6
+ exports.createAtlasDecider = createAtlasDecider;
6
7
  exports.atlasMiddleware = atlasMiddleware;
7
8
  exports.createAuthHelper = createAuthHelper;
8
9
  exports.createCurrentUserHelper = createCurrentUserHelper;
@@ -79,14 +80,19 @@ async function resolveAuth(backend, request) {
79
80
  claims: result.claims,
80
81
  };
81
82
  }
82
- function atlasMiddleware(options) {
83
+ /**
84
+ * The runtime-neutral decision engine behind {@link atlasMiddleware} and
85
+ * `atlasProxy`. Uses only Web-standard APIs (`URL`, `fetch`, Web Crypto), so it
86
+ * runs unchanged on the Edge runtime and on Node.
87
+ */
88
+ function createAtlasDecider(options) {
83
89
  const backend = new backend_1.AtlasBackend({
84
90
  jwksUrl: options.jwksUrl,
85
91
  issuer: options.issuer,
86
92
  authorizedParties: options.authorizedParties,
87
93
  fetchImpl: options.fetchImpl,
88
94
  });
89
- return async function middleware(request, response) {
95
+ return async function decide(request) {
90
96
  /**
91
97
  * Cross-domain satellite RETURN: the handshake endpoint bounced the browser
92
98
  * back with `?__atlas_hs=ok&__atlas_hu=<userId>&__atlas_hn=<nonce>`. Exchange
@@ -123,17 +129,21 @@ function atlasMiddleware(options) {
123
129
  for (const k of ['__atlas_hs', '__atlas_hu', '__atlas_hn'])
124
130
  clean.searchParams.delete(k);
125
131
  if (session) {
126
- const res = response.redirect(clean.toString());
127
- res.cookies?.set('__session', session.jwt, { path: '/', sameSite: 'lax', secure: true });
128
- res.cookies?.set('__atlas_rt', session.refreshToken, {
129
- path: '/',
130
- httpOnly: true,
131
- sameSite: 'lax',
132
- secure: true,
133
- });
134
- // The verifier is spent — clear it so it can't be reused or leak.
135
- res.cookies?.set('__atlas_hv', '', { path: '/', maxAge: 0 });
136
- return res;
132
+ return {
133
+ kind: 'redirect',
134
+ location: clean.toString(),
135
+ auth: exports.SIGNED_OUT,
136
+ cookies: [
137
+ { name: '__session', value: session.jwt, options: { path: '/', sameSite: 'lax', secure: true } },
138
+ {
139
+ name: '__atlas_rt',
140
+ value: session.refreshToken,
141
+ options: { path: '/', httpOnly: true, sameSite: 'lax', secure: true },
142
+ },
143
+ // The verifier is spent — clear it so it can't be reused or leak.
144
+ { name: '__atlas_hv', value: '', options: { path: '/', maxAge: 0 } },
145
+ ],
146
+ };
137
147
  }
138
148
  // A bad/expired/replayed nonce, a rejected PKCE proof, or no verifier →
139
149
  // no session. Carry a SPENT marker (__atlas_hs=failed) instead of a clean
@@ -141,9 +151,12 @@ function atlasMiddleware(options) {
141
151
  // URL here would bounce straight back to the handshake forever. With the
142
152
  // marker, normal routing takes over and sends the user to sign-in.
143
153
  clean.searchParams.set('__atlas_hs', 'failed');
144
- const res = response.redirect(clean.toString());
145
- res.cookies?.set('__atlas_hv', '', { path: '/', maxAge: 0 });
146
- return res;
154
+ return {
155
+ kind: 'redirect',
156
+ location: clean.toString(),
157
+ auth: exports.SIGNED_OUT,
158
+ cookies: [{ name: '__atlas_hv', value: '', options: { path: '/', maxAge: 0 } }],
159
+ };
147
160
  }
148
161
  }
149
162
  const auth = await resolveAuth(backend, request);
@@ -156,9 +169,9 @@ function atlasMiddleware(options) {
156
169
  switch (decision.action) {
157
170
  case 'skip':
158
171
  case 'allow':
159
- return response.next();
172
+ return { kind: 'continue', auth };
160
173
  case 'unauthorized':
161
- return response.json({ errors: [{ code: 'UNAUTHENTICATED' }] }, { status: 401 });
174
+ return { kind: 'unauthorized', auth };
162
175
  case 'redirect': {
163
176
  /**
164
177
  * §R3.1 FIRST, don't bounce a user who is actually signed in here but
@@ -171,7 +184,7 @@ function atlasMiddleware(options) {
171
184
  * common "same-property, token just expired" case never leaves the app.
172
185
  */
173
186
  if (hasSignedInHint(request))
174
- return response.next();
187
+ return { kind: 'continue', auth };
175
188
  /**
176
189
  * Cross-property handshake: before sending a signed-out user to the
177
190
  * sign-in page, try the Atlas handshake ONCE — they may already have a
@@ -193,15 +206,24 @@ function atlasMiddleware(options) {
193
206
  hs.searchParams.set('publishable_key', options.publishableKey);
194
207
  hs.searchParams.set('redirect_url', current.toString());
195
208
  hs.searchParams.set('code_challenge', challenge);
196
- const res = response.redirect(hs.toString());
197
- res.cookies?.set('__atlas_hv', verifier, {
198
- path: '/',
199
- httpOnly: true,
200
- sameSite: 'lax',
201
- secure: true,
202
- maxAge: 300, // the handshake round trip is seconds; don't linger
203
- });
204
- return res;
209
+ return {
210
+ kind: 'redirect',
211
+ location: hs.toString(),
212
+ auth,
213
+ cookies: [
214
+ {
215
+ name: '__atlas_hv',
216
+ value: verifier,
217
+ options: {
218
+ path: '/',
219
+ httpOnly: true,
220
+ sameSite: 'lax',
221
+ secure: true,
222
+ maxAge: 300, // the handshake round trip is seconds; don't linger
223
+ },
224
+ },
225
+ ],
226
+ };
205
227
  }
206
228
  }
207
229
  /**
@@ -211,7 +233,28 @@ function atlasMiddleware(options) {
211
233
  * would otherwise be carried forward unchecked (§13.1).
212
234
  */
213
235
  const base = request.url ? new URL(request.url).origin : '';
214
- return response.redirect(`${base}${decision.to}`);
236
+ return { kind: 'redirect', location: `${base}${decision.to}`, auth, cookies: [] };
237
+ }
238
+ }
239
+ };
240
+ }
241
+ /** The JSON body Atlas answers an unauthenticated API request with. */
242
+ exports.UNAUTHENTICATED_BODY = { errors: [{ code: 'UNAUTHENTICATED' }] };
243
+ function atlasMiddleware(options) {
244
+ const decide = createAtlasDecider(options);
245
+ return async function middleware(request, response) {
246
+ const decision = await decide(request);
247
+ switch (decision.kind) {
248
+ case 'continue':
249
+ return response.next();
250
+ case 'unauthorized':
251
+ return response.json(exports.UNAUTHENTICATED_BODY, { status: 401 });
252
+ case 'redirect': {
253
+ const res = response.redirect(decision.location);
254
+ for (const cookie of decision.cookies) {
255
+ res.cookies?.set(cookie.name, cookie.value, cookie.options);
256
+ }
257
+ return res;
215
258
  }
216
259
  }
217
260
  };
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ import { type AtlasMiddlewareOptions, type AuthState, type EdgeRequest } from './middleware';
2
+ /**
3
+ * Next.js 16 renamed `middleware.ts` to `proxy.ts` (exporting `proxy` or a
4
+ * default function) and made it run on the Node.js runtime by default. A proxy
5
+ * is usually a CHAIN — auth, then i18n (next-intl), then whatever else — so the
6
+ * shape that composes is not "Atlas returns the final response" but "Atlas
7
+ * returns a response only when it must act, otherwise steps aside":
8
+ *
9
+ * ```ts
10
+ * const atlas = atlasProxy({ ... });
11
+ * export async function proxy(req: NextRequest) {
12
+ * return (await atlas(req)) ?? withAtlasHeaders(req, intl(req));
13
+ * }
14
+ * ```
15
+ *
16
+ * `atlas(req)` resolves to a `Response` (sign-in redirect, handshake bounce,
17
+ * 401 for an API route) or `null` (let the app continue). The verified auth
18
+ * state is remembered for that request, so {@link withAtlasHeaders} can forward
19
+ * it to the app on WHATEVER response the rest of the chain produced — without
20
+ * verifying the token a second time and without Atlas having to own the final
21
+ * response.
22
+ *
23
+ * Everything here is Web-standard (`Response`, `Headers`, `URL`, Web Crypto),
24
+ * so the same proxy runs on the Node.js runtime and on the Edge runtime.
25
+ */
26
+ /** Request headers the proxy forwards to the app (server components, route
27
+ * handlers) describing the verified session. */
28
+ export declare const ATLAS_AUTH_HEADERS: {
29
+ readonly status: "x-atlas-auth-status";
30
+ readonly userId: "x-atlas-user-id";
31
+ readonly sessionId: "x-atlas-session-id";
32
+ readonly orgId: "x-atlas-org-id";
33
+ readonly orgRole: "x-atlas-org-role";
34
+ };
35
+ /** What `atlasProxy` needs from a request: a `NextRequest` satisfies it. */
36
+ export interface ProxyRequest extends EdgeRequest {
37
+ headers: {
38
+ get(name: string): string | null;
39
+ forEach(callback: (value: string, key: string) => void): void;
40
+ };
41
+ }
42
+ /** The request-headers slice of a response — `NextResponse` and `Response`
43
+ * both satisfy it. */
44
+ export interface HeaderCarryingResponse {
45
+ status: number;
46
+ headers: Headers;
47
+ }
48
+ export type AtlasProxy = (request: ProxyRequest) => Promise<Response | null>;
49
+ /**
50
+ * The Next.js 16 `proxy.ts` entry for Atlas. Same options, same decisions as
51
+ * `atlasMiddleware` (they share one engine) — only the calling convention
52
+ * differs: it takes just the request and resolves to `Response | null`.
53
+ */
54
+ export declare function atlasProxy(options: AtlasMiddlewareOptions): AtlasProxy;
55
+ /**
56
+ * The auth state the proxy resolved for this request (signed-out if the proxy
57
+ * hasn't run on it). For extra checks inside `proxy.ts` itself — a role gate on
58
+ * `/admin`, say — without verifying the token again.
59
+ */
60
+ export declare function proxyAuth(request: object): AuthState;
61
+ /**
62
+ * Forward the verified session to the app as `x-atlas-*` REQUEST headers on a
63
+ * response produced by any later step of the chain (`NextResponse.next()`, a
64
+ * next-intl rewrite, …). Returns the same response, for `return withAtlasHeaders(...)`.
65
+ *
66
+ * It speaks Next's request-header override protocol (what
67
+ * `NextResponse.next({ request: { headers } })` emits), MERGING with any
68
+ * override a previous step already set rather than clobbering it, so it composes
69
+ * with next-intl or your own header tweaks in either order.
70
+ *
71
+ * Any `x-atlas-*` header the CLIENT sent is always dropped — a browser can't
72
+ * forge `x-atlas-user-id` past the proxy. Responses that don't continue to the
73
+ * app (redirects, direct bodies) are returned untouched: there's no downstream
74
+ * request to carry headers.
75
+ *
76
+ * `auth` defaults to what {@link atlasProxy} resolved for `request`, or
77
+ * signed-out if it didn't run.
78
+ */
79
+ export declare function withAtlasHeaders<R extends HeaderCarryingResponse>(request: ProxyRequest, response: R, auth?: AuthState): R;
80
+ /** The session as forwarded by {@link withAtlasHeaders}. */
81
+ export interface ForwardedAuth {
82
+ signedIn: boolean;
83
+ userId: string | null;
84
+ sessionId: string | null;
85
+ orgId: string | null;
86
+ orgRole: string | null;
87
+ }
88
+ /**
89
+ * Read the `x-atlas-*` headers the proxy forwarded (e.g. from `await headers()`
90
+ * in a server component). Cheap — no verification — so use it for rendering
91
+ * decisions; keep authorization on `auth()`/`protect()`, which verify the token
92
+ * themselves and don't depend on the proxy's matcher covering the route.
93
+ */
94
+ export declare function readAtlasHeaders(headers: {
95
+ get(name: string): string | null;
96
+ }): ForwardedAuth;
package/dist/proxy.js ADDED
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ATLAS_AUTH_HEADERS = void 0;
4
+ exports.atlasProxy = atlasProxy;
5
+ exports.proxyAuth = proxyAuth;
6
+ exports.withAtlasHeaders = withAtlasHeaders;
7
+ exports.readAtlasHeaders = readAtlasHeaders;
8
+ const middleware_1 = require("./middleware");
9
+ /**
10
+ * Next.js 16 renamed `middleware.ts` to `proxy.ts` (exporting `proxy` or a
11
+ * default function) and made it run on the Node.js runtime by default. A proxy
12
+ * is usually a CHAIN — auth, then i18n (next-intl), then whatever else — so the
13
+ * shape that composes is not "Atlas returns the final response" but "Atlas
14
+ * returns a response only when it must act, otherwise steps aside":
15
+ *
16
+ * ```ts
17
+ * const atlas = atlasProxy({ ... });
18
+ * export async function proxy(req: NextRequest) {
19
+ * return (await atlas(req)) ?? withAtlasHeaders(req, intl(req));
20
+ * }
21
+ * ```
22
+ *
23
+ * `atlas(req)` resolves to a `Response` (sign-in redirect, handshake bounce,
24
+ * 401 for an API route) or `null` (let the app continue). The verified auth
25
+ * state is remembered for that request, so {@link withAtlasHeaders} can forward
26
+ * it to the app on WHATEVER response the rest of the chain produced — without
27
+ * verifying the token a second time and without Atlas having to own the final
28
+ * response.
29
+ *
30
+ * Everything here is Web-standard (`Response`, `Headers`, `URL`, Web Crypto),
31
+ * so the same proxy runs on the Node.js runtime and on the Edge runtime.
32
+ */
33
+ /** Request headers the proxy forwards to the app (server components, route
34
+ * handlers) describing the verified session. */
35
+ exports.ATLAS_AUTH_HEADERS = {
36
+ status: 'x-atlas-auth-status',
37
+ userId: 'x-atlas-user-id',
38
+ sessionId: 'x-atlas-session-id',
39
+ orgId: 'x-atlas-org-id',
40
+ orgRole: 'x-atlas-org-role',
41
+ };
42
+ const ATLAS_HEADER_PREFIX = 'x-atlas-';
43
+ const OVERRIDE_LIST = 'x-middleware-override-headers';
44
+ const OVERRIDE_PREFIX = 'x-middleware-request-';
45
+ /** Auth state per request, recorded by the proxy for `withAtlasHeaders` /
46
+ * `proxyAuth`. Weak, so a finished request's state is collected with it. */
47
+ const resolved = new WeakMap();
48
+ function serializeCookie({ name, value, options }) {
49
+ // Same encoding Next's `response.cookies.set` applies, so readers agree.
50
+ const parts = [`${name}=${encodeURIComponent(value)}`];
51
+ if (options.path)
52
+ parts.push(`Path=${options.path}`);
53
+ if (options.maxAge !== undefined)
54
+ parts.push(`Max-Age=${options.maxAge}`);
55
+ if (options.httpOnly)
56
+ parts.push('HttpOnly');
57
+ if (options.secure)
58
+ parts.push('Secure');
59
+ if (options.sameSite) {
60
+ parts.push(`SameSite=${options.sameSite[0].toUpperCase()}${options.sameSite.slice(1)}`);
61
+ }
62
+ return parts.join('; ');
63
+ }
64
+ /**
65
+ * The Next.js 16 `proxy.ts` entry for Atlas. Same options, same decisions as
66
+ * `atlasMiddleware` (they share one engine) — only the calling convention
67
+ * differs: it takes just the request and resolves to `Response | null`.
68
+ */
69
+ function atlasProxy(options) {
70
+ const decide = (0, middleware_1.createAtlasDecider)(options);
71
+ return async function proxy(request) {
72
+ const decision = await decide(request);
73
+ resolved.set(request, decision.auth);
74
+ switch (decision.kind) {
75
+ case 'continue':
76
+ return null;
77
+ case 'unauthorized':
78
+ return new Response(JSON.stringify(middleware_1.UNAUTHENTICATED_BODY), {
79
+ status: 401,
80
+ headers: { 'content-type': 'application/json' },
81
+ });
82
+ case 'redirect': {
83
+ // Built by hand rather than `Response.redirect`, whose headers are
84
+ // immutable — the handshake legs must also set first-party cookies.
85
+ const headers = new Headers({ location: decision.location });
86
+ for (const cookie of decision.cookies)
87
+ headers.append('set-cookie', serializeCookie(cookie));
88
+ return new Response(null, { status: 307, headers });
89
+ }
90
+ }
91
+ };
92
+ }
93
+ /**
94
+ * The auth state the proxy resolved for this request (signed-out if the proxy
95
+ * hasn't run on it). For extra checks inside `proxy.ts` itself — a role gate on
96
+ * `/admin`, say — without verifying the token again.
97
+ */
98
+ function proxyAuth(request) {
99
+ return resolved.get(request) ?? middleware_1.SIGNED_OUT;
100
+ }
101
+ function authHeaderValues(auth) {
102
+ const values = [
103
+ [exports.ATLAS_AUTH_HEADERS.status, auth.userId ? 'signed-in' : 'signed-out'],
104
+ ];
105
+ if (auth.userId)
106
+ values.push([exports.ATLAS_AUTH_HEADERS.userId, auth.userId]);
107
+ if (auth.sessionId)
108
+ values.push([exports.ATLAS_AUTH_HEADERS.sessionId, auth.sessionId]);
109
+ if (auth.orgId)
110
+ values.push([exports.ATLAS_AUTH_HEADERS.orgId, auth.orgId]);
111
+ if (auth.orgRole)
112
+ values.push([exports.ATLAS_AUTH_HEADERS.orgRole, auth.orgRole]);
113
+ return values;
114
+ }
115
+ /**
116
+ * Forward the verified session to the app as `x-atlas-*` REQUEST headers on a
117
+ * response produced by any later step of the chain (`NextResponse.next()`, a
118
+ * next-intl rewrite, …). Returns the same response, for `return withAtlasHeaders(...)`.
119
+ *
120
+ * It speaks Next's request-header override protocol (what
121
+ * `NextResponse.next({ request: { headers } })` emits), MERGING with any
122
+ * override a previous step already set rather than clobbering it, so it composes
123
+ * with next-intl or your own header tweaks in either order.
124
+ *
125
+ * Any `x-atlas-*` header the CLIENT sent is always dropped — a browser can't
126
+ * forge `x-atlas-user-id` past the proxy. Responses that don't continue to the
127
+ * app (redirects, direct bodies) are returned untouched: there's no downstream
128
+ * request to carry headers.
129
+ *
130
+ * `auth` defaults to what {@link atlasProxy} resolved for `request`, or
131
+ * signed-out if it didn't run.
132
+ */
133
+ function withAtlasHeaders(request, response, auth = proxyAuth(request)) {
134
+ const continues = response.headers.has('x-middleware-next') || response.headers.has('x-middleware-rewrite');
135
+ if (!continues)
136
+ return response;
137
+ const existing = response.headers.get(OVERRIDE_LIST);
138
+ const names = new Set();
139
+ if (existing !== null) {
140
+ // An earlier step already chose the full downstream header set; keep its
141
+ // choices and only take over the `x-atlas-*` namespace.
142
+ for (const raw of existing.split(',')) {
143
+ const name = raw.trim().toLowerCase();
144
+ if (!name)
145
+ continue;
146
+ if (name.startsWith(ATLAS_HEADER_PREFIX)) {
147
+ response.headers.delete(`${OVERRIDE_PREFIX}${name}`);
148
+ }
149
+ else {
150
+ names.add(name);
151
+ }
152
+ }
153
+ }
154
+ else {
155
+ // First override: start from the incoming request headers, as
156
+ // `NextResponse.next({ request: { headers: new Headers(req.headers) } })` does.
157
+ request.headers.forEach((value, key) => {
158
+ const name = key.toLowerCase();
159
+ if (name.startsWith(ATLAS_HEADER_PREFIX))
160
+ return;
161
+ names.add(name);
162
+ response.headers.set(`${OVERRIDE_PREFIX}${name}`, value);
163
+ });
164
+ }
165
+ for (const [name, value] of authHeaderValues(auth)) {
166
+ names.add(name);
167
+ response.headers.set(`${OVERRIDE_PREFIX}${name}`, value);
168
+ }
169
+ response.headers.set(OVERRIDE_LIST, [...names].join(','));
170
+ return response;
171
+ }
172
+ /**
173
+ * Read the `x-atlas-*` headers the proxy forwarded (e.g. from `await headers()`
174
+ * in a server component). Cheap — no verification — so use it for rendering
175
+ * decisions; keep authorization on `auth()`/`protect()`, which verify the token
176
+ * themselves and don't depend on the proxy's matcher covering the route.
177
+ */
178
+ function readAtlasHeaders(headers) {
179
+ const userId = headers.get(exports.ATLAS_AUTH_HEADERS.userId);
180
+ const signedIn = headers.get(exports.ATLAS_AUTH_HEADERS.status) === 'signed-in' && Boolean(userId);
181
+ return {
182
+ signedIn,
183
+ userId: signedIn ? userId : null,
184
+ sessionId: signedIn ? headers.get(exports.ATLAS_AUTH_HEADERS.sessionId) : null,
185
+ orgId: signedIn ? headers.get(exports.ATLAS_AUTH_HEADERS.orgId) : null,
186
+ orgRole: signedIn ? headers.get(exports.ATLAS_AUTH_HEADERS.orgRole) : null,
187
+ };
188
+ }
189
+ //# sourceMappingURL=proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlasauth/nextjs",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "exports": {
@@ -15,7 +15,7 @@
15
15
  "./package.json": "./package.json"
16
16
  },
17
17
  "dependencies": {
18
- "@atlasauth/backend": "0.1.2"
18
+ "@atlasauth/backend": "0.7.0"
19
19
  },
20
20
  "peerDependencies": {
21
21
  "next": ">=13.4"
@@ -36,7 +36,8 @@
36
36
  },
37
37
  "files": [
38
38
  "dist",
39
- "README.md"
39
+ "README.md",
40
+ "CHANGELOG.md"
40
41
  ],
41
42
  "scripts": {
42
43
  "build": "tsc -p tsconfig.build.json",