@grantry/nextjs 0.0.0-stage → 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Grantry
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,110 @@
1
- # Temporary Holding Version
1
+ # @grantry/nextjs
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Grantry authentication for Next.js: the React components and hooks, `auth()` for server
4
+ components, route handlers and server actions, and a middleware that keeps signed-out visitors
5
+ off protected routes.
6
+
7
+ ```sh
8
+ npm install @grantry/nextjs
9
+ ```
10
+
11
+ Requires Next.js 15 or 16 and React 18 or 19. Everything `@grantry/react` exports is
12
+ re-exported here, so a Next.js application does not install it separately.
13
+
14
+ ## Setup
15
+
16
+ Set your publishable key (Grantry dashboard, API keys):
17
+
18
+ ```sh
19
+ NEXT_PUBLIC_GRANTRY_PUBLISHABLE_KEY=pk_live_...
20
+ ```
21
+
22
+ Wrap the application in the provider:
23
+
24
+ ```tsx
25
+ // app/layout.tsx
26
+ import { GrantryProvider } from '@grantry/nextjs';
27
+
28
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
29
+ return (
30
+ <html lang="en">
31
+ <body>
32
+ <GrantryProvider publishableKey={process.env.NEXT_PUBLIC_GRANTRY_PUBLISHABLE_KEY!}>
33
+ {children}
34
+ </GrantryProvider>
35
+ </body>
36
+ </html>
37
+ );
38
+ }
39
+ ```
40
+
41
+ ## Reading the visitor on the server
42
+
43
+ ```tsx
44
+ import { auth } from '@grantry/nextjs/server';
45
+
46
+ export default async function Page() {
47
+ const { userId } = await auth();
48
+ if (!userId) return <p>Signed out</p>;
49
+ return <p>Signed in as {userId}</p>;
50
+ }
51
+ ```
52
+
53
+ `auth()` verifies the `grantry_token` cookie against Grantry's published signing keys, which are
54
+ fetched once and cached; no request is made per render after that. It checks the signature, the
55
+ expiry, the issuer and that the token belongs to *your* application, read from the publishable
56
+ key. With no publishable key configured it throws `no_audience` rather than accept a token minted
57
+ for another application.
58
+
59
+ `requireAuth()` is the same but throws when nobody is signed in. For the Pages Router, or anything
60
+ else that cannot call `next/headers`, verify the cookie yourself with `verifyToken`, which is also
61
+ exported from `@grantry/nextjs/server`.
62
+
63
+ ## Protecting routes
64
+
65
+ ```ts
66
+ // proxy.ts (Next.js 16) or middleware.ts (Next.js 15)
67
+ import { grantryMiddleware } from '@grantry/nextjs/middleware';
68
+
69
+ export default grantryMiddleware({
70
+ protectedRoutes: ['/dashboard', '/account'],
71
+ signInUrl: '/sign-in',
72
+ });
73
+
74
+ export const config = { matcher: ['/((?!_next|.*\\..*).*)'] };
75
+ ```
76
+
77
+ A string protects that path and everything under it; pass a `RegExp` for anything else. Only what
78
+ is listed is protected. A signed-out visitor is redirected to the sign-in page with `redirect_url`
79
+ set to where they were going. A verified request goes on with `x-grantry-user-id` and
80
+ `x-grantry-session-id` set; those headers are removed from every request the middleware sees, but
81
+ a route outside the `matcher` never reaches it, so `auth()` is the safer read.
82
+
83
+ With no `signInUrl`, the middleware uses `GRANTRY_SIGN_IN_URL`, then
84
+ `NEXT_PUBLIC_GRANTRY_SIGN_IN_URL`, then the environment's hosted sign-in page, and answers `401`
85
+ if there is none.
86
+
87
+ ## Environment variables
88
+
89
+ | Variable | Read by |
90
+ | --- | --- |
91
+ | `NEXT_PUBLIC_GRANTRY_PUBLISHABLE_KEY` | `auth()`, the middleware (and pass it to the provider) |
92
+ | `GRANTRY_PUBLISHABLE_KEY` | `auth()` and the middleware, before the public one |
93
+ | `NEXT_PUBLIC_GRANTRY_SIGN_IN_URL` | the provider and the middleware (after `GRANTRY_SIGN_IN_URL`) |
94
+ | `NEXT_PUBLIC_GRANTRY_SIGN_UP_URL` | the provider |
95
+ | `NEXT_PUBLIC_GRANTRY_SIGN_IN_FALLBACK_REDIRECT_URL`, `..._SIGN_UP_FALLBACK_REDIRECT_URL` | the provider |
96
+ | `NEXT_PUBLIC_GRANTRY_SIGN_IN_FORCE_REDIRECT_URL`, `..._SIGN_UP_FORCE_REDIRECT_URL` | the provider |
97
+ | `NEXT_PUBLIC_GRANTRY_AFTER_SIGN_OUT_URL` | the provider |
98
+
99
+ No secret key is needed or read by this package.
100
+
101
+ ## About the token cookie
102
+
103
+ The browser SDK mirrors the short-lived access token into a `grantry_token` cookie on your domain
104
+ (`SameSite=Lax`, `Secure` on HTTPS) so the server can see who is signed in. A cookie written by
105
+ script cannot be `httpOnly`; the token lives about a minute and cannot mint another, and the
106
+ credential that can stays `httpOnly` on Grantry's domain.
107
+
108
+ ## License
109
+
110
+ MIT
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The access-token cookie, as the middleware and `auth()` both read it.
3
+ *
4
+ * ⚠️ ONE COPY OF THE NAME, AND A TEST HOLDS IT TO `@grantry/js`. It cannot be imported from there:
5
+ * this package depends on `@grantry/react` alone, and `@grantry/react`'s main entry is the browser
6
+ * half, which has no business in a middleware bundle. `server.ts` and `middleware.ts` each carried
7
+ * their own literal, one under a comment saying it was imported; `tests/cookie.test.ts` compares
8
+ * this one with the writer's.
9
+ */
10
+ export declare const TOKEN_COOKIE_NAME = "grantry_token";
11
+ /**
12
+ * The token in the cookie as Next.js hands it over, or null when there is none.
13
+ *
14
+ * ⚠️ NOT DECODED A SECOND TIME. Next's cookie parser already applies `decodeURIComponent` to every
15
+ * value, and both readers applied it again. A JWT never contains `%`, so the second pass changed
16
+ * nothing for a real token — and threw `URIError` for a cookie whose decoded value held a stray
17
+ * `%E0`. In `auth()` that error was not a `TokenVerificationError`, so it was rethrown and every
18
+ * server component calling `auth()` failed to render for that visitor. Anything other than a token
19
+ * that is still left is reported by `verifyToken` as `malformed`.
20
+ */
21
+ export declare function tokenFromCookie(cookie: {
22
+ value: string;
23
+ } | undefined): string | null;
24
+ //# sourceMappingURL=cookie.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookie.d.ts","sourceRoot":"","sources":["../src/cookie.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,kBAAkB,CAAC;AAEjD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAEpF"}
package/dist/cookie.js ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The access-token cookie, as the middleware and `auth()` both read it.
3
+ *
4
+ * ⚠️ ONE COPY OF THE NAME, AND A TEST HOLDS IT TO `@grantry/js`. It cannot be imported from there:
5
+ * this package depends on `@grantry/react` alone, and `@grantry/react`'s main entry is the browser
6
+ * half, which has no business in a middleware bundle. `server.ts` and `middleware.ts` each carried
7
+ * their own literal, one under a comment saying it was imported; `tests/cookie.test.ts` compares
8
+ * this one with the writer's.
9
+ */
10
+ export const TOKEN_COOKIE_NAME = 'grantry_token';
11
+ /**
12
+ * The token in the cookie as Next.js hands it over, or null when there is none.
13
+ *
14
+ * ⚠️ NOT DECODED A SECOND TIME. Next's cookie parser already applies `decodeURIComponent` to every
15
+ * value, and both readers applied it again. A JWT never contains `%`, so the second pass changed
16
+ * nothing for a real token — and threw `URIError` for a cookie whose decoded value held a stray
17
+ * `%E0`. In `auth()` that error was not a `TokenVerificationError`, so it was rethrown and every
18
+ * server component calling `auth()` failed to render for that visitor. Anything other than a token
19
+ * that is still left is reported by `verifyToken` as `malformed`.
20
+ */
21
+ export function tokenFromCookie(cookie) {
22
+ return cookie?.value || null;
23
+ }
24
+ //# sourceMappingURL=cookie.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookie.js","sourceRoot":"","sources":["../src/cookie.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAEjD;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAC,MAAqC;IACnE,OAAO,MAAM,EAAE,KAAK,IAAI,IAAI,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @grantry/nextjs — authentication for Next.js.
3
+ *
4
+ * app/layout.tsx <GrantryProvider> (client)
5
+ * app/page.tsx await auth() (server)
6
+ * middleware.ts grantryMiddleware() (edge)
7
+ *
8
+ * ⚠️ A RE-EXPORT, NOT A SECOND IMPLEMENTATION. Everything below is the React
9
+ * SDK unchanged, so a Next.js application installs one dependency and imports
10
+ * the same names it would in any React app — and there is no second copy of a
11
+ * component to drift from the first. The Next-specific half is `./server` and
12
+ * `./middleware`, which is genuinely different code.
13
+ *
14
+ * The one exception is `GrantryProvider`, which is a four-line wrapper around
15
+ * the React one for the sole purpose of saying "nextjs" rather than "react" on
16
+ * the wire. See `./provider` for why that distinction has to exist at all.
17
+ *
18
+ * ⚠️ EVERY NAME `@grantry/react` EXPORTS IS LISTED HERE, AND A TEST HOLDS IT TO
19
+ * THAT. The list is by name, with no `export *`, so for months each new React
20
+ * export was simply absent from Next.js:
21
+ * `AuthCard`, `OAuthConsent`, the localization contract and the entitlement
22
+ * helpers all had documentation pages telling Next.js readers to import them
23
+ * from here. `packages/sdk-react/tests/nextjs-exports.test.ts` compares the two
24
+ * lists, types included, and fails on the next one.
25
+ */
26
+ export { GrantryProvider } from './provider.js';
27
+ export { useAuth, useUser, useSession, useAccounts, useOAuth, useGrantry, useEntitlements, readOAuthResult, usePlans, pricingCatalogue, formatMoney, useRoutes, mergeRouteOptions, redirectTarget, requestedRedirectUrl, useSignInFlow, useSignUpFlow, entitlementsFromToken, actorFromToken, checkEntitlements, EMPTY_ENTITLEMENTS, SignedIn, SignedOut, GrantryLoading, GrantryLoaded, GrantryDegraded, GrantryFailed, useEnvironmentStatus, Protect, SignOutButton, useSignOutAction, SignIn, SignUp, CompleteAccount, UserButton, isAddingAccount, addAccountUrl, ADD_ACCOUNT_PARAM, UserAvatar, Waitlist, ResetPassword, SetupMfa, UserProfile, PricingTable, CheckoutButton, PlanDetailsButton, SubscriptionDetailsButton, ProductCard, type ProductCardProps, MenuItems, CustomAction, CustomLink, CustomPage, AuthCard, OAuthConsent, ContinueAs, ImpersonationBanner, LocalizationProvider, useTranslate, EN, AppearanceProvider, GRANTRY_STYLES, useStylesheet, variablesToStyle, THEME_COLORS, THEME_COLOR_LABELS, THEME_FONTS, THEME_LOGO_PLACEMENTS, THEME_RADII, THEME_SOCIAL_PLACEMENTS, THEME_SOCIAL_VARIANTS, brandThemeAppearance, cleanBrandTheme, themeColorScheme, DEFAULT_AVATAR_COLORS, avatarBackgroundCss, avatarInitial, avatarSeed, GrantryClient, GrantryError, TOKEN_COOKIE_NAME, useReverification, type Reverify, type ReverifyOptions, type Reverification, type ReverificationGrant, type ReverificationMethod, type GrantryProviderProps, type GrantryPreview, type SignInHostProviderProps, type ResellerHostProviderProps, type Routes, type RouteOptions, type RedirectTargets, type TokenEntitlements, type HasParams, type UseEntitlementsReturn, type SignInStatus, type SignUpStatus, type ProtectProps, type AuthCardProps, type OAuthConsentProps, type ContinueAsProps, type Localization, type LocalizationInput, type GrantryClientOptions, type SignUpParams, type SignUpResult, type BackupCodesProof, type BackupCodeEntry, type RevealedBackupCodes, type ChangeQuote, type CouponPreview, type FieldIssue, type BrandTheme, type ThemeColor, type ThemeFont, type ThemeProblem, type ThemeRadius, type AvatarStyle, type AvatarBackground, type AvatarForeground, type GrantryUser, type GrantrySession, type GrantryTrustedDevice, type GrantryBoundDevice, type GrantryBoundDevices, type GrantryAccount, type GrantryEnvironment, type GrantryErrorCode, type SignInResult, type Appearance, type ElementDescriptor, type ElementsConfig, type ElementStyle, type AppearanceVariables, type AppearanceLayout, type EnvironmentStatus, type SignOutButtonProps, type UseSignOutAction, type SignInProps, type SignUpProps, type CompleteAccountProps, type UserButtonProps, type UserProfileProps, type UseAuthReturn, type UseUserReturn, type UseSessionReturn, type UseAccountsReturn, type UseOAuthReturn, type UseSignInFlow, type UseSignUpFlow, type OAuthProviderInfo, type ConnectedAccount, type GrantryAuthorizedApp, type MfaFactor, type UserEmailAddress, type PublicPlan, type PlanPrice, type PlansResponse, type BillingSummary, type UsePlansOptions, type UsePlansReturn, type PricingCatalogue, type PricingPlan, type PricingPlanPrice, type PlanIntervalUnit, } from '@grantry/react';
28
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @grantry/nextjs — authentication for Next.js.
3
+ *
4
+ * app/layout.tsx <GrantryProvider> (client)
5
+ * app/page.tsx await auth() (server)
6
+ * middleware.ts grantryMiddleware() (edge)
7
+ *
8
+ * ⚠️ A RE-EXPORT, NOT A SECOND IMPLEMENTATION. Everything below is the React
9
+ * SDK unchanged, so a Next.js application installs one dependency and imports
10
+ * the same names it would in any React app — and there is no second copy of a
11
+ * component to drift from the first. The Next-specific half is `./server` and
12
+ * `./middleware`, which is genuinely different code.
13
+ *
14
+ * The one exception is `GrantryProvider`, which is a four-line wrapper around
15
+ * the React one for the sole purpose of saying "nextjs" rather than "react" on
16
+ * the wire. See `./provider` for why that distinction has to exist at all.
17
+ *
18
+ * ⚠️ EVERY NAME `@grantry/react` EXPORTS IS LISTED HERE, AND A TEST HOLDS IT TO
19
+ * THAT. The list is by name, with no `export *`, so for months each new React
20
+ * export was simply absent from Next.js:
21
+ * `AuthCard`, `OAuthConsent`, the localization contract and the entitlement
22
+ * helpers all had documentation pages telling Next.js readers to import them
23
+ * from here. `packages/sdk-react/tests/nextjs-exports.test.ts` compares the two
24
+ * lists, types included, and fails on the next one.
25
+ */
26
+ export { GrantryProvider } from './provider.js';
27
+ export {
28
+ // Hooks
29
+ useAuth, useUser, useSession, useAccounts, useOAuth, useGrantry, useEntitlements, readOAuthResult,
30
+ // The public plans, for pricing cards of your own
31
+ usePlans, pricingCatalogue, formatMoney,
32
+ // Where the application's own pages are: the provider's route options and their helpers.
33
+ useRoutes, mergeRouteOptions, redirectTarget, requestedRedirectUrl,
34
+ // Headless flows
35
+ useSignInFlow, useSignUpFlow,
36
+ // Entitlements, read straight off an access token
37
+ entitlementsFromToken, actorFromToken, checkEntitlements, EMPTY_ENTITLEMENTS,
38
+ // Control
39
+ SignedIn, SignedOut, GrantryLoading, GrantryLoaded,
40
+ /*
41
+ * ⚠️ THE CONNECTION PAIR, WHICH IS NOT THE SESSION PAIR. See the React
42
+ * package's `control.tsx` for why they are separate rather than four states
43
+ * of one machine the way Clerk's are.
44
+ */
45
+ GrantryDegraded, GrantryFailed, useEnvironmentStatus, Protect,
46
+ // Unstyled actions
47
+ SignOutButton, useSignOutAction,
48
+ // Drop-in components. Cut from a release and back; see the React package's
49
+ // index for what changed on the way back in (the default look, not the code).
50
+ SignIn, SignUp,
51
+ /*
52
+ * ⚠️ RE-EXPORTED BY NAME, SO A NEW COMPONENT IS UNREACHABLE FROM NEXT.JS
53
+ * UNTIL IT IS LISTED HERE. `<SignIn />` draws this itself when the account
54
+ * owes something, but an application that redirects somewhere other than its
55
+ * sign-in route has to render it there.
56
+ */
57
+ CompleteAccount, UserButton,
58
+ /*
59
+ * ⚠️ NOT A COMPONENT, AND IT HAS TO BE HERE ANYWAY. `<UserButton />` sends
60
+ * "Add account" to the sign-in page with a marker on the link, and a Next.js
61
+ * application cannot let that visitor past its own gate without this. The
62
+ * list above is by name, so an unlisted helper is the same as one that does
63
+ * not exist -- and the failure is a redirect loop in somebody else's app.
64
+ */
65
+ isAddingAccount, addAccountUrl, ADD_ACCOUNT_PARAM,
66
+ /*
67
+ * ⚠️ FOUR COMPONENTS THAT WERE EXPORTED FROM REACT AND UNREACHABLE FROM HERE,
68
+ * which is the same as not existing for a Next.js application — this list is
69
+ * by name and there is no deep-import escape hatch.
70
+ */
71
+ UserAvatar, Waitlist, ResetPassword, SetupMfa, UserProfile, PricingTable, CheckoutButton, PlanDetailsButton, SubscriptionDetailsButton, ProductCard, MenuItems, CustomAction, CustomLink, CustomPage,
72
+ // The card itself, the consent card, "Continue as" and the support-visit banner.
73
+ AuthCard, OAuthConsent, ContinueAs, ImpersonationBanner,
74
+ // Localization
75
+ LocalizationProvider, useTranslate, EN,
76
+ // Appearance
77
+ AppearanceProvider, GRANTRY_STYLES, useStylesheet, variablesToStyle,
78
+ // The brand theme: what Hosted sign-in → Theme stores, the hosted screens' look
79
+ THEME_COLORS, THEME_COLOR_LABELS, THEME_FONTS, THEME_LOGO_PLACEMENTS, THEME_RADII, THEME_SOCIAL_PLACEMENTS, THEME_SOCIAL_VARIANTS, brandThemeAppearance, cleanBrandTheme, themeColorScheme,
80
+ // Avatars, drawn as the components draw them
81
+ DEFAULT_AVATAR_COLORS, avatarBackgroundCss, avatarInitial, avatarSeed,
82
+ // The client
83
+ GrantryClient, GrantryError, TOKEN_COOKIE_NAME,
84
+ // "Verify it's you" (0330): the dialog before a sensitive action, and what it resolves with.
85
+ useReverification, } from '@grantry/react';
86
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO;AACL,QAAQ;AACR,OAAO,EACP,OAAO,EACP,UAAU,EACV,WAAW,EACX,QAAQ,EACR,UAAU,EACV,eAAe,EACf,eAAe;AACf,kDAAkD;AAClD,QAAQ,EACR,gBAAgB,EAChB,WAAW;AAEX,yFAAyF;AACzF,SAAS,EACT,iBAAiB,EACjB,cAAc,EACd,oBAAoB;AAEpB,iBAAiB;AACjB,aAAa,EACb,aAAa;AAEb,kDAAkD;AAClD,qBAAqB,EACrB,cAAc,EACd,iBAAiB,EACjB,kBAAkB;AAElB,UAAU;AACV,QAAQ,EACR,SAAS,EACT,cAAc,EACd,aAAa;AACb;;;;GAIG;AACH,eAAe,EACf,aAAa,EACb,oBAAoB,EACpB,OAAO;AAEP,mBAAmB;AACnB,aAAa,EACb,gBAAgB;AAEhB,2EAA2E;AAC3E,8EAA8E;AAC9E,MAAM,EACN,MAAM;AACN;;;;;GAKG;AACH,eAAe,EACf,UAAU;AACV;;;;;;GAMG;AACH,eAAe,EACf,aAAa,EACb,iBAAiB;AACjB;;;;GAIG;AACH,UAAU,EACV,QAAQ,EACR,aAAa,EACb,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,yBAAyB,EACzB,WAAW,EAEX,SAAS,EACT,YAAY,EACZ,UAAU,EACV,UAAU;AACV,iFAAiF;AACjF,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,mBAAmB;AAEnB,eAAe;AACf,oBAAoB,EACpB,YAAY,EACZ,EAAE;AAEF,aAAa;AACb,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,gBAAgB;AAEhB,gFAAgF;AAChF,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,qBAAqB,EACrB,WAAW,EACX,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,EACf,gBAAgB;AAEhB,6CAA6C;AAC7C,qBAAqB,EACrB,mBAAmB,EACnB,aAAa,EACb,UAAU;AAEV,aAAa;AACb,aAAa,EACb,YAAY,EACZ,iBAAiB;AAEjB,6FAA6F;AAC7F,iBAAiB,GAuFlB,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Route protection in Next.js middleware — `@grantry/nextjs/middleware`.
3
+ *
4
+ * export default grantryMiddleware({
5
+ * protectedRoutes: ['/dashboard', '/account'],
6
+ * signInUrl: '/sign-in',
7
+ * });
8
+ *
9
+ * export const config = { matcher: ['/((?!_next|.*\\..*).*)'] };
10
+ *
11
+ * Middleware runs before rendering, so an unauthenticated visitor is redirected
12
+ * without the protected page ever being built — which is the difference between
13
+ * protecting a route and merely hiding it. No request is let through signed out,
14
+ * a support visit's included; see `visitTicket`.
15
+ */
16
+ import { NextResponse, type NextRequest } from 'next/server';
17
+ export interface GrantryMiddlewareOptions {
18
+ /**
19
+ * Path patterns requiring a signed-in visitor.
20
+ *
21
+ * A path prefix as a string — `'/dashboard'` protects it and everything under
22
+ * it — or a `RegExp` for anything else. `'/dashboard(.*)'`, the spelling other
23
+ * libraries use, means the same prefix; any other string that looks like a
24
+ * pattern is refused when the middleware is made (`prefixOf`).
25
+ * Anything not listed is public — an allowlist would silently protect new
26
+ * routes, which sounds safer but produces a site where adding a public page
27
+ * quietly breaks it.
28
+ */
29
+ protectedRoutes?: Array<string | RegExp>;
30
+ /**
31
+ * Where to send unauthenticated visitors.
32
+ *
33
+ * Unset: `GRANTRY_SIGN_IN_URL`, then `NEXT_PUBLIC_GRANTRY_SIGN_IN_URL` — the
34
+ * variable `<GrantryProvider>` reads, so the two agree — then the hosted
35
+ * sign-in screen on the environment's sign-in URL, which is looked up with the
36
+ * publishable key (one request, remembered for five minutes). With none of
37
+ * those the visitor is answered 401 (docs/paths-and-domains.md §6).
38
+ * ⚠️ It defaulted to `/sign-in`, a page Grantry could only guess the
39
+ * application had.
40
+ */
41
+ signInUrl?: string;
42
+ /** Override for self-hosted deployments and local development. */
43
+ apiUrl?: string;
44
+ /**
45
+ * Your publishable key, which names the application these tokens must belong
46
+ * to, and finds the hosted sign-in screen when no sign-in page is named. Read
47
+ * from `GRANTRY_PUBLISHABLE_KEY`, then `NEXT_PUBLIC_GRANTRY_PUBLISHABLE_KEY`,
48
+ * when omitted. ⚠️ With no key and no `environmentId`, a request carrying a
49
+ * token makes the middleware THROW (`no_audience`) rather than redirect — no
50
+ * token is ever admitted without knowing the application, and a sign-in page
51
+ * cannot fix a server that does not know which one it is. See
52
+ * `@grantry/react/server`.
53
+ */
54
+ publishableKey?: string;
55
+ /** The environment id, for a deployment that configures it directly. */
56
+ environmentId?: string;
57
+ /** Require a verified email address, not merely a session. */
58
+ requireVerifiedEmail?: boolean;
59
+ }
60
+ /**
61
+ * A string route pattern, as the path prefix it protects.
62
+ *
63
+ * ⚠️ `'/dashboard(.*)'` PROTECTED NOTHING UNTIL 1 OCTOBER 2026, AND THE DOCS SAID TO WRITE IT. A
64
+ * string was compared as a literal prefix, so the pattern matched only a path that began with the
65
+ * characters `/dashboard(.*)` — none — and the middleware let every request through, signed out.
66
+ * The quickstart, the middleware page and this file's own example all used it (the docs audit). It
67
+ * is the spelling Clerk's route matcher takes, so somebody arriving from there writes it too: it is
68
+ * read as the prefix it means, and anything else that looks like a pattern is refused rather than
69
+ * silently matched against nothing.
70
+ */
71
+ export declare function prefixOf(pattern: string): string;
72
+ export declare function grantryMiddleware(options?: GrantryMiddlewareOptions): (request: NextRequest) => Promise<NextResponse>;
73
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAsB7D,MAAM,WAAW,wBAAwB;IACvC;;;;;;;;;;OAUG;IACH,eAAe,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IACzC;;;;;;;;;;OAUG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;;OASG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8DAA8D;IAC9D,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAUhD;AAuED,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,IAiCrC,SAAS,WAAW,KAAG,OAAO,CAAC,YAAY,CAAC,CAqF9E"}
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Route protection in Next.js middleware — `@grantry/nextjs/middleware`.
3
+ *
4
+ * export default grantryMiddleware({
5
+ * protectedRoutes: ['/dashboard', '/account'],
6
+ * signInUrl: '/sign-in',
7
+ * });
8
+ *
9
+ * export const config = { matcher: ['/((?!_next|.*\\..*).*)'] };
10
+ *
11
+ * Middleware runs before rendering, so an unauthenticated visitor is redirected
12
+ * without the protected page ever being built — which is the difference between
13
+ * protecting a route and merely hiding it. No request is let through signed out,
14
+ * a support visit's included; see `visitTicket`.
15
+ */
16
+ import { NextResponse } from 'next/server';
17
+ import { REDIRECT_URL_PARAMETER, TICKET_PARAMETER, environmentSignInUrl, hostedSignInPage, serverRouteOptions, verifyToken, } from '@grantry/react/server';
18
+ import { TOKEN_COOKIE_NAME, tokenFromCookie } from './cookie.js';
19
+ /**
20
+ * The headers a verified request goes on with, for the application's pages to read.
21
+ *
22
+ * ⚠️ REMOVED FROM EVERY REQUEST THIS MIDDLEWARE SEES, NOT ONLY THE ONES IT VERIFIES. They were
23
+ * replaced on a protected route and passed through untouched everywhere else, so a visitor who sent
24
+ * `x-grantry-user-id: <anybody>` to a public page had it arrive as though this middleware had set
25
+ * it — and the docs tell a page it can trust these names. A page outside the middleware's `matcher`
26
+ * is still beyond reach, which is why `auth()`, which verifies the cookie itself, is the safer read.
27
+ */
28
+ const FORWARDED_HEADERS = ['x-grantry-user-id', 'x-grantry-session-id'];
29
+ /**
30
+ * A string route pattern, as the path prefix it protects.
31
+ *
32
+ * ⚠️ `'/dashboard(.*)'` PROTECTED NOTHING UNTIL 1 OCTOBER 2026, AND THE DOCS SAID TO WRITE IT. A
33
+ * string was compared as a literal prefix, so the pattern matched only a path that began with the
34
+ * characters `/dashboard(.*)` — none — and the middleware let every request through, signed out.
35
+ * The quickstart, the middleware page and this file's own example all used it (the docs audit). It
36
+ * is the spelling Clerk's route matcher takes, so somebody arriving from there writes it too: it is
37
+ * read as the prefix it means, and anything else that looks like a pattern is refused rather than
38
+ * silently matched against nothing.
39
+ */
40
+ export function prefixOf(pattern) {
41
+ const prefix = pattern.endsWith('(.*)') ? pattern.slice(0, -'(.*)'.length) : pattern;
42
+ if (/[()*?+[\]{}|^$\\]/u.test(prefix)) {
43
+ throw new Error(`Grantry: the route pattern "${pattern}" is not a path prefix. ` +
44
+ 'Use a prefix such as "/dashboard", or pass a RegExp.');
45
+ }
46
+ const trimmed = prefix.replace(/\/+$/u, '');
47
+ return trimmed === '' ? '/' : trimmed;
48
+ }
49
+ function matchesPath(pathname, patterns) {
50
+ return patterns.some((pattern) => {
51
+ if (typeof pattern === 'string') {
52
+ // A prefix, anchored at a path boundary so `/dashboard` does not also
53
+ // protect `/dashboards-public`.
54
+ return pattern === '/' || pathname === pattern || pathname.startsWith(`${pattern}/`);
55
+ }
56
+ /*
57
+ * ⚠️ `lastIndex` RESET FIRST. A RegExp with the `g` or `y` flag remembers where its last match
58
+ * ended and starts the next `test` there, so `/^\/admin/g` matched one request, missed the
59
+ * next — letting it through signed out — and matched the one after.
60
+ */
61
+ pattern.lastIndex = 0;
62
+ return pattern.test(pathname);
63
+ });
64
+ }
65
+ /**
66
+ * Whether a path is protected, as written and as decoded.
67
+ *
68
+ * ⚠️ BOTH SPELLINGS, BECAUSE THE ROUTER AND THIS CHECK MAY NOT AGREE ON ONE. `nextUrl.pathname`
69
+ * keeps percent-encoding (`/%64ashboard`), and a router that decodes before it matches a page
70
+ * would build `/dashboard` for an address the prefix never saw. Matching the decoded path too
71
+ * costs nothing on an ordinary request and only ever protects more.
72
+ */
73
+ function matches(pathname, patterns) {
74
+ if (matchesPath(pathname, patterns))
75
+ return true;
76
+ let decoded;
77
+ try {
78
+ decoded = decodeURIComponent(pathname);
79
+ }
80
+ catch {
81
+ return false;
82
+ }
83
+ return decoded !== pathname && matchesPath(decoded, patterns);
84
+ }
85
+ /** The request as the application will see it, with no forwarded header the visitor wrote. */
86
+ function withoutForwardedHeaders(request) {
87
+ const headers = new Headers(request.headers);
88
+ for (const name of FORWARDED_HEADERS)
89
+ headers.delete(name);
90
+ return headers;
91
+ }
92
+ /**
93
+ * A support visit's first request: a navigation carrying `?__grantry_ticket=`.
94
+ *
95
+ * ⚠️ CARRIED TO SIGN-IN, NEVER LET THROUGH. A view-as link opens the Home URL
96
+ * with its ticket (0242), and `@grantry/js` spends it on whatever page loads. A
97
+ * plain redirect to sign-in dropped the query string, so a protected Home URL
98
+ * turned every visit into a sign-in form for an operator with no password to
99
+ * type — and the first fix, letting the request through signed out, was a way
100
+ * past this middleware for anybody: the ticket is not checked here, so adding
101
+ * the parameter to any protected address rendered that page to a signed-out
102
+ * visitor. A page that trusted this middleware to keep its data from signed-out
103
+ * visitors would have served it.
104
+ *
105
+ * So the ticket rides the redirect instead. The sign-in page is public, the SDK
106
+ * spends the ticket there before anything else runs, and `<SignIn />` moves a
107
+ * visit on to `redirect_url` — the address the link pointed at, without the
108
+ * ticket. The protected page is only ever built for a signed-in request.
109
+ *
110
+ * Only GET and HEAD: a form post or a server action is never a navigation from a
111
+ * link, and carries nothing anywhere.
112
+ */
113
+ function visitTicket(request) {
114
+ if (request.method !== 'GET' && request.method !== 'HEAD')
115
+ return null;
116
+ return request.nextUrl.searchParams.get(TICKET_PARAMETER) || null;
117
+ }
118
+ export function grantryMiddleware(options = {}) {
119
+ const { protectedRoutes: patterns = [], apiUrl, publishableKey, environmentId, requireVerifiedEmail = false, } = options;
120
+ // Read once, here, so a pattern that cannot work fails the deploy and not a visitor.
121
+ const protectedRoutes = patterns.map((pattern) => typeof pattern === 'string' ? prefixOf(pattern) : pattern);
122
+ /**
123
+ * Where sign-in is: the option, the server's variables, the hosted sign-in screen.
124
+ *
125
+ * ⚠️ THE ONE SDK THAT DOES NOT DEFAULT TO REDIRECT SIGN-IN, because it cannot.
126
+ * A redirect sign-in keeps its verifier in the browser and spends its code
127
+ * there (docs/hosted-sign-in.md §6), and the only page this middleware knows
128
+ * is the protected one it is turning the visitor away from. Name a sign-in
129
+ * page — `<SignIn mode="redirect" />` makes one a single line.
130
+ */
131
+ async function signInPage() {
132
+ const configured = options.signInUrl ?? serverRouteOptions().signInUrl;
133
+ if (configured)
134
+ return configured;
135
+ const signInUrl = await environmentSignInUrl({
136
+ ...(publishableKey ? { publishableKey } : {}),
137
+ ...(apiUrl ? { apiUrl } : {}),
138
+ });
139
+ return hostedSignInPage(signInUrl, 'sign-in');
140
+ }
141
+ return async function middleware(request) {
142
+ if (!matches(request.nextUrl.pathname, protectedRoutes)) {
143
+ // A public page: through, with nothing that claims to be this middleware's word.
144
+ return FORWARDED_HEADERS.some((name) => request.headers.has(name))
145
+ ? NextResponse.next({ request: { headers: withoutForwardedHeaders(request) } })
146
+ : NextResponse.next();
147
+ }
148
+ const token = tokenFromCookie(request.cookies.get(TOKEN_COOKIE_NAME));
149
+ const turnAway = async () => {
150
+ const signIn = await signInPage();
151
+ if (!signIn) {
152
+ return new NextResponse('Sign-in is required, and this application has no sign-in page.', {
153
+ status: 401,
154
+ });
155
+ }
156
+ const target = new URL(signIn, request.url);
157
+ const here = new URL(request.url);
158
+ // A support visit: the sign-in page spends the ticket, and the visit goes on to
159
+ // where the link pointed, without it. See `visitTicket`.
160
+ const ticket = visitTicket(request);
161
+ if (ticket) {
162
+ here.searchParams.delete(TICKET_PARAMETER);
163
+ target.searchParams.set(TICKET_PARAMETER, ticket);
164
+ }
165
+ /*
166
+ * So the app can return the visitor where they were headed rather than
167
+ * dumping them on a home page after signing in. ⚠️ A PATH WHEN SIGN-IN IS
168
+ * ON THIS ORIGIN, THE WHOLE ADDRESS WHEN IT IS NOT: on the hosted sign-in
169
+ * screen a path would name a page of the sign-in URL's. The query
170
+ * string goes too: `/dashboard?tab=billing` came back as `/dashboard`.
171
+ * The sign-in page follows it only on its own origin (`requestedRedirectUrl`).
172
+ */
173
+ target.searchParams.set(REDIRECT_URL_PARAMETER, target.origin === here.origin ? `${here.pathname}${here.search}` : here.href);
174
+ const response = NextResponse.redirect(target);
175
+ // The ticket is in this address; the page it leads to has no need to be told where it came from.
176
+ if (ticket)
177
+ response.headers.set('Referrer-Policy', 'no-referrer');
178
+ return response;
179
+ };
180
+ if (!token)
181
+ return turnAway();
182
+ try {
183
+ const verified = await verifyToken(token, {
184
+ ...(apiUrl ? { apiUrl } : {}),
185
+ ...(publishableKey ? { publishableKey } : {}),
186
+ ...(environmentId ? { environmentId } : {}),
187
+ });
188
+ if (requireVerifiedEmail && !verified.emailVerified) {
189
+ return turnAway();
190
+ }
191
+ // Passed to the application so a server component can read the user
192
+ // without verifying a second time. Set on the *outgoing* request headers,
193
+ // which the visitor cannot forge — anything they send under these names
194
+ // is replaced here (and removed on public pages; see `FORWARDED_HEADERS`).
195
+ const headers = withoutForwardedHeaders(request);
196
+ headers.set('x-grantry-user-id', verified.userId);
197
+ headers.set('x-grantry-session-id', verified.sessionId);
198
+ return NextResponse.next({ request: { headers } });
199
+ }
200
+ catch (cause) {
201
+ /*
202
+ * ⚠️ A MISSING AUDIENCE IS THE ONE FAILURE THAT MUST NOT REDIRECT. Every
203
+ * other reason means this request cannot be trusted, and the sign-in page
204
+ * is the honest answer; `no_audience` means the application never said
205
+ * which Grantry environment it belongs to, and sending the visitor to
206
+ * sign in would loop them forever against a check that can never pass.
207
+ */
208
+ if (cause instanceof Error &&
209
+ cause.name === 'TokenVerificationError' &&
210
+ cause.reason === 'no_audience') {
211
+ throw cause;
212
+ }
213
+ return turnAway();
214
+ }
215
+ };
216
+ }
217
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}