@authgear/nextjs 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/README.md ADDED
@@ -0,0 +1,307 @@
1
+ # Authgear SDK for Next.js
2
+
3
+ [![@authgear/nextjs](https://img.shields.io/npm/v/@authgear/nextjs.svg?label=@authgear/nextjs)](https://www.npmjs.com/package/@authgear/nextjs)
4
+ [![@authgear/nextjs](https://img.shields.io/npm/dt/@authgear/nextjs.svg?label=@authgear/nextjs)](https://www.npmjs.com/package/@authgear/nextjs)
5
+ ![License](https://img.shields.io/badge/license-MIT-blue)
6
+
7
+ With Authgear SDK for Next.js, you can easily integrate authentication features into your Next.js application โ€” covering both the frontend and backend in one package.
8
+ In most cases, it involves just **a few lines of code** to enable **multiple authentication methods**, such as [social logins](https://www.authgear.com/features/social-login), [passwordless](https://www.authgear.com/features/passwordless-authentication), [biometrics logins](https://www.authgear.com/features/biometric-authentication), [one-time-password (OTP)](https://www.authgear.com/features/whatsapp-otp) with SMS/WhatsApp, and multi-factor authentication (MFA).
9
+
10
+ **Quick links** โ€” ๐Ÿ“š [Documentation](#documentation) ยท ๐Ÿ [Getting Started](#getting-started) ยท ๐Ÿ› ๏ธ [Troubleshooting](#troubleshooting) ยท ๐Ÿ‘ฅ [Contributing](#contributing)
11
+
12
+ ## What is Authgear?
13
+
14
+ [Authgear](https://www.authgear.com/) is a highly adaptable identity-as-a-service (IDaaS) platform for web and mobile applications.
15
+ Authgear makes user authentication easier and faster to implement by integrating it into various types of applications โ€” from single-page web apps to mobile applications to API services.
16
+
17
+ ### Key Features
18
+
19
+ - Zero-trust authentication architecture with [OpenID Connect](https://openid.net/developers/how-connect-works/) (OIDC) standard.
20
+ - Easy-to-use interfaces for user registration and login, including email, phone, username as login ID, and password, OTP, magic links, etc.
21
+ - Support for a wide range of identity providers, such as [Google](https://developers.google.com/identity), [Apple](https://support.apple.com/en-gb/guide/deployment/depa64848f3a/web), and [Azure Active Directory](https://azure.microsoft.com/en-gb/products/active-directory/).
22
+ - Support for Passkeys, biometric login, and Multi-Factor Authentication (MFA) such as SMS/email-based verification and authenticator apps with TOTP.
23
+
24
+ ## Requirements
25
+
26
+ - **Next.js** >= 16.0.0
27
+ - **React** >= 19.0.0
28
+ - **Node.js** >= 18
29
+
30
+ ## Installation
31
+
32
+ ```sh
33
+ npm install @authgear/nextjs
34
+ ```
35
+
36
+ ## Getting Started
37
+
38
+ ### 1. Configure Authgear
39
+
40
+ Create a config object. The `sessionSecret` must be at least 32 characters and should be stored in an environment variable.
41
+
42
+ ```ts
43
+ // lib/authgear.ts
44
+ import type { AuthgearConfig } from "@authgear/nextjs";
45
+
46
+ export const authgearConfig: AuthgearConfig = {
47
+ endpoint: process.env.AUTHGEAR_ENDPOINT!, // e.g. "https://myapp.authgear.cloud"
48
+ clientID: process.env.AUTHGEAR_CLIENT_ID!,
49
+ clientSecret: process.env.AUTHGEAR_CLIENT_SECRET, // for confidential clients
50
+ redirectURI: process.env.AUTHGEAR_REDIRECT_URI!, // e.g. "http://localhost:3000/api/auth/callback"
51
+ sessionSecret: process.env.SESSION_SECRET!, // min 32 chars
52
+ };
53
+ ```
54
+
55
+ ### 2. Add the Route Handler
56
+
57
+ Create a catch-all route to handle all auth endpoints (`/api/auth/login`, `/api/auth/callback`, `/api/auth/logout`, `/api/auth/refresh`, `/api/auth/userinfo`).
58
+
59
+ ```ts
60
+ // app/api/auth/[...authgear]/route.ts
61
+ import { createAuthgearHandlers } from "@authgear/nextjs";
62
+ import { authgearConfig } from "@/lib/authgear";
63
+
64
+ export const { GET, POST } = createAuthgearHandlers(authgearConfig);
65
+ ```
66
+
67
+ ### 3. Add the Provider (Client Components)
68
+
69
+ Wrap your app with `AuthgearProvider` to enable client-side hooks and components.
70
+
71
+ ```tsx
72
+ // app/layout.tsx
73
+ import { AuthgearProvider } from "@authgear/nextjs/client";
74
+
75
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
76
+ return (
77
+ <html>
78
+ <body>
79
+ <AuthgearProvider>{children}</AuthgearProvider>
80
+ </body>
81
+ </html>
82
+ );
83
+ }
84
+ ```
85
+
86
+ ### 4. Protect Routes with the Proxy (Next.js 16)
87
+
88
+ Create a `proxy.ts` file at the root of your project to automatically redirect unauthenticated users and inject auth headers.
89
+
90
+ ```ts
91
+ // proxy.ts
92
+ import { createAuthgearProxy } from "@authgear/nextjs/proxy";
93
+ import { authgearConfig } from "@/lib/authgear";
94
+
95
+ export const proxy = createAuthgearProxy({
96
+ ...authgearConfig,
97
+ protectedPaths: ["/dashboard/*", "/profile/*"],
98
+ });
99
+ ```
100
+
101
+ ---
102
+
103
+ ## Usage
104
+
105
+ ### Client Components
106
+
107
+ Use the `useAuthgear` hook or the built-in buttons:
108
+
109
+ ```tsx
110
+ "use client";
111
+
112
+ import { useAuthgear, SignInButton, SignOutButton } from "@authgear/nextjs/client";
113
+
114
+ export function NavBar() {
115
+ const { isAuthenticated, isLoaded, user } = useAuthgear();
116
+
117
+ if (!isLoaded) return null;
118
+
119
+ return isAuthenticated ? (
120
+ <div>
121
+ <span>Welcome, {user?.email}</span>
122
+ <SignOutButton />
123
+ </div>
124
+ ) : (
125
+ <SignInButton />
126
+ );
127
+ }
128
+ ```
129
+
130
+ ### Server Components
131
+
132
+ Use `currentUser()` to get the authenticated user in Server Components and Route Handlers.
133
+
134
+ ```tsx
135
+ // app/dashboard/page.tsx
136
+ import { currentUser } from "@authgear/nextjs/server";
137
+ import { authgearConfig } from "@/lib/authgear";
138
+ import { redirect } from "next/navigation";
139
+
140
+ export default async function DashboardPage() {
141
+ const user = await currentUser(authgearConfig);
142
+ if (!user) redirect("/api/auth/login?returnTo=/dashboard");
143
+
144
+ return <h1>Hello, {user.email}</h1>;
145
+ }
146
+ ```
147
+
148
+ ### Protecting API Routes with JWT
149
+
150
+ Use `verifyAccessToken()` to validate a Bearer token in API routes.
151
+
152
+ ```ts
153
+ // app/api/me/route.ts
154
+ import { verifyAccessToken } from "@authgear/nextjs/server";
155
+ import { authgearConfig } from "@/lib/authgear";
156
+ import { NextRequest, NextResponse } from "next/server";
157
+
158
+ export async function GET(request: NextRequest) {
159
+ const authHeader = request.headers.get("Authorization");
160
+ const token = authHeader?.replace("Bearer ", "");
161
+ if (!token) return NextResponse.json({ error: "unauthorized" }, { status: 401 });
162
+
163
+ try {
164
+ const payload = await verifyAccessToken(token, authgearConfig);
165
+ return NextResponse.json({ sub: payload.sub });
166
+ } catch {
167
+ return NextResponse.json({ error: "invalid_token" }, { status: 401 });
168
+ }
169
+ }
170
+ ```
171
+
172
+ ### Reading the Session
173
+
174
+ Use `auth()` to read the raw session (tokens + expiry) without fetching user info.
175
+
176
+ ```ts
177
+ import { auth } from "@authgear/nextjs/server";
178
+ import { authgearConfig } from "@/lib/authgear";
179
+
180
+ const session = await auth(authgearConfig);
181
+ // session.state: SessionState.Authenticated | SessionState.NoSession
182
+ // session.accessToken: string | null
183
+ ```
184
+
185
+ ---
186
+
187
+ ## API Reference
188
+
189
+ ### `@authgear/nextjs`
190
+
191
+ | Export | Description |
192
+ |---|---|
193
+ | `createAuthgearHandlers(config)` | Returns `{ GET, POST }` for `app/api/auth/[...authgear]/route.ts` |
194
+
195
+ ### `@authgear/nextjs/server`
196
+
197
+ | Export | Description |
198
+ |---|---|
199
+ | `auth(config)` | Returns the current `Session` from the session cookie |
200
+ | `currentUser(config)` | Returns `UserInfo \| null`, auto-refreshes access token |
201
+ | `verifyAccessToken(token, config)` | Verifies a JWT Bearer token with JWKS, returns `JWTPayload` |
202
+
203
+ ### `@authgear/nextjs/client`
204
+
205
+ | Export | Description |
206
+ |---|---|
207
+ | `<AuthgearProvider>` | React context provider, must wrap the app |
208
+ | `useAuthgear()` | Returns `{ state, user, isLoaded, isAuthenticated, signIn, signOut }` |
209
+ | `useUser()` | Returns `UserInfo \| null` |
210
+ | `<SignInButton>` | Button that calls `signIn()` on click |
211
+ | `<SignOutButton>` | Button that calls `signOut()` on click |
212
+
213
+ ### `@authgear/nextjs/proxy`
214
+
215
+ | Export | Description |
216
+ |---|---|
217
+ | `createAuthgearProxy(options)` | Returns a Next.js 16 `proxy()` function |
218
+
219
+ **`createAuthgearProxy` options** (extends `AuthgearConfig`):
220
+
221
+ | Option | Default | Description |
222
+ |---|---|---|
223
+ | `protectedPaths` | `[]` | Paths requiring auth, supports `*` suffix (e.g. `"/dashboard/*"`) |
224
+ | `publicPaths` | `["/api/auth/*"]` | Paths always allowed through |
225
+ | `loginPath` | `"/api/auth/login"` | Where to redirect unauthenticated users |
226
+
227
+ ### `AuthgearConfig`
228
+
229
+ | Field | Required | Description |
230
+ |---|---|---|
231
+ | `endpoint` | โœ“ | Authgear endpoint, e.g. `"https://myapp.authgear.cloud"` |
232
+ | `clientID` | โœ“ | OAuth client ID |
233
+ | `redirectURI` | โœ“ | OAuth callback URL, e.g. `"http://localhost:3000/api/auth/callback"` |
234
+ | `sessionSecret` | โœ“ | Secret for encrypting session cookie (min 32 chars) |
235
+ | `clientSecret` | | OAuth client secret (for confidential clients) |
236
+ | `postLogoutRedirectURI` | | Where to redirect after logout. Defaults to `"/"` |
237
+ | `scopes` | | OAuth scopes. Defaults to `["openid", "offline_access", "https://authgear.com/scopes/full-userinfo"]` |
238
+ | `cookieName` | | Session cookie name. Defaults to `"authgear.session"` |
239
+
240
+ ---
241
+
242
+ ## Roadmap
243
+
244
+ ### `open(page)` โ€” Open Authgear Settings Page
245
+
246
+ > **Status: pending server-side enablement**
247
+
248
+ The SDK has a planned `getOpenURL(page, config)` function (modelled after [`authgear.open(Page.Settings)`](https://docs.authgear.com/get-started/single-page-app/website#step-8-open-user-settings-page) in the web SDK) that opens the Authgear-hosted settings UI with the current user already authenticated โ€” no re-login required.
249
+
250
+ **How it will work:**
251
+
252
+ ```ts
253
+ // app/dashboard/actions.ts (Server Action)
254
+ "use server";
255
+ import { getOpenURL, Page } from "@authgear/nextjs/server";
256
+ import { authgearConfig } from "@/lib/authgear";
257
+
258
+ export async function getSettingsURLAction() {
259
+ return getOpenURL(Page.Settings, authgearConfig);
260
+ }
261
+ ```
262
+
263
+ ```tsx
264
+ // Client component
265
+ const url = await getSettingsURLAction();
266
+ window.open(url, "_blank");
267
+ ```
268
+
269
+ **Blocker:** This feature exchanges the refresh token for an `app_session_token` via `POST /oauth2/app_session_token`. The Authgear server must grant the OAuth client **"full user access"** permission before this endpoint is accessible. Once that server-side configuration is in place, the implementation in `src/server.ts` can be uncommented and released.
270
+
271
+ ---
272
+
273
+ ## Documentation
274
+
275
+ - Learn how to set up an Authgear application at [https://docs.authgear.com/](https://docs.authgear.com/)
276
+ - Learn how to manage your users through the [Admin API](https://docs.authgear.com/reference/apis/admin-api)
277
+
278
+ ## Troubleshooting
279
+
280
+ Please check out the [Get Help](https://github.com/orgs/authgear/discussions/categories/get-help) section for solutions to common issues.
281
+
282
+ ### Raise an Issue
283
+
284
+ To provide feedback or report a bug, please [raise an issue on our issue tracker](https://github.com/authgear/authgear-sdk-js/issues).
285
+
286
+ ## Contributing
287
+
288
+ Anyone who wishes to contribute to this project, whether documentation, features, bug fixes, code cleanup, testing, or code reviews, is very much encouraged to do so.
289
+
290
+ To join, raise your hand on the [Authgear Discord server](https://discord.gg/Kdn5vcYwAS) or the GitHub [discussions board](https://github.com/orgs/authgear/discussions).
291
+
292
+ ```sh
293
+ git clone git@github.com:authgear/authgear-sdk-nextjs.git
294
+ cd authgear-sdk-nextjs
295
+ npm install
296
+ npm test
297
+ ```
298
+
299
+ ## Supported and maintained by
300
+
301
+ <div align="center">
302
+ <a href="https://github.com/authgear"><img src="https://uploads-ssl.webflow.com/60658b46b03f0cf83ac1485d/619e6607eb647619cecee2cf_authgear-logo.svg" /></a>
303
+ </div>
304
+
305
+ <p align="center">
306
+ Authgear is a highly adaptable identity-as-a-service (IDaaS) platform for web and mobile applications. To learn more, visit <a href="https://www.authgear.com/">authgear.com</a>.
307
+ </p>
@@ -0,0 +1,26 @@
1
+ // src/user.ts
2
+ function parseUserInfo(raw) {
3
+ return {
4
+ sub: raw["sub"],
5
+ email: raw["email"],
6
+ emailVerified: raw["email_verified"],
7
+ phoneNumber: raw["phone_number"],
8
+ phoneNumberVerified: raw["phone_number_verified"],
9
+ preferredUsername: raw["preferred_username"],
10
+ givenName: raw["given_name"],
11
+ familyName: raw["family_name"],
12
+ name: raw["name"],
13
+ picture: raw["picture"],
14
+ roles: raw["https://authgear.com/claims/user/roles"],
15
+ isAnonymous: raw["https://authgear.com/claims/user/is_anonymous"],
16
+ isVerified: raw["https://authgear.com/claims/user/is_verified"],
17
+ canReauthenticate: raw["https://authgear.com/claims/user/can_reauthenticate"],
18
+ customAttributes: raw["custom_attributes"],
19
+ raw
20
+ };
21
+ }
22
+
23
+ export {
24
+ parseUserInfo
25
+ };
26
+ //# sourceMappingURL=chunk-3KVYAFQJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/user.ts"],"sourcesContent":["import type { UserInfo } from \"./types.js\";\n\nexport function parseUserInfo(raw: Record<string, unknown>): UserInfo {\n return {\n sub: raw[\"sub\"] as string,\n email: raw[\"email\"] as string | undefined,\n emailVerified: raw[\"email_verified\"] as boolean | undefined,\n phoneNumber: raw[\"phone_number\"] as string | undefined,\n phoneNumberVerified: raw[\"phone_number_verified\"] as boolean | undefined,\n preferredUsername: raw[\"preferred_username\"] as string | undefined,\n givenName: raw[\"given_name\"] as string | undefined,\n familyName: raw[\"family_name\"] as string | undefined,\n name: raw[\"name\"] as string | undefined,\n picture: raw[\"picture\"] as string | undefined,\n roles: raw[\"https://authgear.com/claims/user/roles\"] as string[] | undefined,\n isAnonymous: raw[\"https://authgear.com/claims/user/is_anonymous\"] as boolean | undefined,\n isVerified: raw[\"https://authgear.com/claims/user/is_verified\"] as boolean | undefined,\n canReauthenticate: raw[\"https://authgear.com/claims/user/can_reauthenticate\"] as boolean | undefined,\n customAttributes: raw[\"custom_attributes\"] as Record<string, unknown> | undefined,\n raw,\n };\n}\n"],"mappings":";AAEO,SAAS,cAAc,KAAwC;AACpE,SAAO;AAAA,IACL,KAAK,IAAI,KAAK;AAAA,IACd,OAAO,IAAI,OAAO;AAAA,IAClB,eAAe,IAAI,gBAAgB;AAAA,IACnC,aAAa,IAAI,cAAc;AAAA,IAC/B,qBAAqB,IAAI,uBAAuB;AAAA,IAChD,mBAAmB,IAAI,oBAAoB;AAAA,IAC3C,WAAW,IAAI,YAAY;AAAA,IAC3B,YAAY,IAAI,aAAa;AAAA,IAC7B,MAAM,IAAI,MAAM;AAAA,IAChB,SAAS,IAAI,SAAS;AAAA,IACtB,OAAO,IAAI,wCAAwC;AAAA,IACnD,aAAa,IAAI,+CAA+C;AAAA,IAChE,YAAY,IAAI,8CAA8C;AAAA,IAC9D,mBAAmB,IAAI,qDAAqD;AAAA,IAC5E,kBAAkB,IAAI,mBAAmB;AAAA,IACzC;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,227 @@
1
+ import {
2
+ DEFAULT_SCOPES
3
+ } from "./chunk-UY6NEM2T.js";
4
+
5
+ // src/config.ts
6
+ function resolveConfig(config) {
7
+ if (!config.endpoint) throw new Error("AuthgearConfig: endpoint is required");
8
+ if (!config.clientID) throw new Error("AuthgearConfig: clientID is required");
9
+ if (!config.redirectURI) throw new Error("AuthgearConfig: redirectURI is required");
10
+ if (!config.sessionSecret || config.sessionSecret.length < 32) {
11
+ throw new Error("AuthgearConfig: sessionSecret must be at least 32 characters");
12
+ }
13
+ return {
14
+ endpoint: config.endpoint.replace(/\/+$/, ""),
15
+ clientID: config.clientID,
16
+ clientSecret: config.clientSecret ?? "",
17
+ redirectURI: config.redirectURI,
18
+ postLogoutRedirectURI: config.postLogoutRedirectURI ?? "/",
19
+ scopes: config.scopes ?? DEFAULT_SCOPES,
20
+ sessionSecret: config.sessionSecret,
21
+ cookieName: config.cookieName ?? "authgear.session"
22
+ };
23
+ }
24
+
25
+ // src/oauth/discovery.ts
26
+ var cache = /* @__PURE__ */ new Map();
27
+ var CACHE_TTL_MS = 60 * 60 * 1e3;
28
+ async function fetchOIDCConfiguration(endpoint) {
29
+ const cached = cache.get(endpoint);
30
+ if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
31
+ return cached.config;
32
+ }
33
+ const url = `${endpoint}/.well-known/openid-configuration`;
34
+ const res = await fetch(url);
35
+ if (!res.ok) {
36
+ throw new Error(`Failed to fetch OIDC configuration from ${url}: ${res.status}`);
37
+ }
38
+ const config = await res.json();
39
+ cache.set(endpoint, { config, fetchedAt: Date.now() });
40
+ return config;
41
+ }
42
+
43
+ // src/session/cookie.ts
44
+ import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "crypto";
45
+ var ALGORITHM = "aes-256-gcm";
46
+ var IV_LENGTH = 12;
47
+ var AUTH_TAG_LENGTH = 16;
48
+ var KEY_LENGTH = 32;
49
+ var SALT = "authgear-nextjs-session";
50
+ function deriveKey(secret) {
51
+ return scryptSync(secret, SALT, KEY_LENGTH);
52
+ }
53
+ function encryptSession(data, secret) {
54
+ const key = deriveKey(secret);
55
+ const iv = randomBytes(IV_LENGTH);
56
+ const cipher = createCipheriv(ALGORITHM, key, iv, { authTagLength: AUTH_TAG_LENGTH });
57
+ const json = JSON.stringify(data);
58
+ const encrypted = Buffer.concat([cipher.update(json, "utf8"), cipher.final()]);
59
+ const authTag = cipher.getAuthTag();
60
+ return Buffer.concat([iv, authTag, encrypted]).toString("base64url");
61
+ }
62
+ function decryptSession(encrypted, secret) {
63
+ try {
64
+ const key = deriveKey(secret);
65
+ const buf = Buffer.from(encrypted, "base64url");
66
+ if (buf.length < IV_LENGTH + AUTH_TAG_LENGTH) return null;
67
+ const iv = buf.subarray(0, IV_LENGTH);
68
+ const authTag = buf.subarray(IV_LENGTH, IV_LENGTH + AUTH_TAG_LENGTH);
69
+ const ciphertext = buf.subarray(IV_LENGTH + AUTH_TAG_LENGTH);
70
+ const decipher = createDecipheriv(ALGORITHM, key, iv, { authTagLength: AUTH_TAG_LENGTH });
71
+ decipher.setAuthTag(authTag);
72
+ const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
73
+ return JSON.parse(decrypted.toString("utf8"));
74
+ } catch {
75
+ return null;
76
+ }
77
+ }
78
+ function buildSessionCookie(cookieName, data, secret) {
79
+ return {
80
+ name: cookieName,
81
+ value: encryptSession(data, secret),
82
+ httpOnly: true,
83
+ secure: process.env.NODE_ENV === "production",
84
+ sameSite: "lax",
85
+ path: "/",
86
+ maxAge: 30 * 24 * 60 * 60
87
+ // 30 days
88
+ };
89
+ }
90
+ function buildClearCookie(cookieName) {
91
+ return {
92
+ name: cookieName,
93
+ value: "",
94
+ httpOnly: true,
95
+ secure: process.env.NODE_ENV === "production",
96
+ sameSite: "lax",
97
+ path: "/",
98
+ maxAge: 0
99
+ };
100
+ }
101
+ function buildPKCECookie(data, secret) {
102
+ const key = deriveKey(secret);
103
+ const iv = randomBytes(IV_LENGTH);
104
+ const cipher = createCipheriv(ALGORITHM, key, iv, { authTagLength: AUTH_TAG_LENGTH });
105
+ const json = JSON.stringify(data);
106
+ const encrypted = Buffer.concat([cipher.update(json, "utf8"), cipher.final()]);
107
+ const authTag = cipher.getAuthTag();
108
+ return {
109
+ name: "authgear.pkce",
110
+ value: Buffer.concat([iv, authTag, encrypted]).toString("base64url"),
111
+ httpOnly: true,
112
+ secure: process.env.NODE_ENV === "production",
113
+ sameSite: "lax",
114
+ path: "/",
115
+ maxAge: 600
116
+ // 10 minutes
117
+ };
118
+ }
119
+ function decryptPKCECookie(encrypted, secret) {
120
+ try {
121
+ const key = deriveKey(secret);
122
+ const buf = Buffer.from(encrypted, "base64url");
123
+ if (buf.length < IV_LENGTH + AUTH_TAG_LENGTH) return null;
124
+ const iv = buf.subarray(0, IV_LENGTH);
125
+ const authTag = buf.subarray(IV_LENGTH, IV_LENGTH + AUTH_TAG_LENGTH);
126
+ const ciphertext = buf.subarray(IV_LENGTH + AUTH_TAG_LENGTH);
127
+ const decipher = createDecipheriv(ALGORITHM, key, iv, { authTagLength: AUTH_TAG_LENGTH });
128
+ decipher.setAuthTag(authTag);
129
+ const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
130
+ return JSON.parse(decrypted.toString("utf8"));
131
+ } catch {
132
+ return null;
133
+ }
134
+ }
135
+
136
+ // src/oauth/token.ts
137
+ async function exchangeCode(oidcConfig, params) {
138
+ const body = new URLSearchParams({
139
+ grant_type: "authorization_code",
140
+ code: params.code,
141
+ code_verifier: params.codeVerifier,
142
+ client_id: params.clientID,
143
+ redirect_uri: params.redirectURI
144
+ });
145
+ if (params.clientSecret) {
146
+ body.set("client_secret", params.clientSecret);
147
+ }
148
+ const res = await fetch(oidcConfig.token_endpoint, {
149
+ method: "POST",
150
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
151
+ body: body.toString()
152
+ });
153
+ if (!res.ok) {
154
+ const error = await res.text();
155
+ throw new Error(`Token exchange failed (${res.status}): ${error}`);
156
+ }
157
+ return res.json();
158
+ }
159
+ async function refreshAccessToken(oidcConfig, params) {
160
+ const body = new URLSearchParams({
161
+ grant_type: "refresh_token",
162
+ refresh_token: params.refreshToken,
163
+ client_id: params.clientID
164
+ });
165
+ if (params.clientSecret) {
166
+ body.set("client_secret", params.clientSecret);
167
+ }
168
+ const res = await fetch(oidcConfig.token_endpoint, {
169
+ method: "POST",
170
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
171
+ body: body.toString()
172
+ });
173
+ if (!res.ok) {
174
+ const error = await res.text();
175
+ throw new Error(`Token refresh failed (${res.status}): ${error}`);
176
+ }
177
+ return res.json();
178
+ }
179
+ async function revokeToken(oidcConfig, token) {
180
+ await fetch(oidcConfig.revocation_endpoint, {
181
+ method: "POST",
182
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
183
+ body: new URLSearchParams({ token }).toString()
184
+ });
185
+ }
186
+
187
+ // src/session/state.ts
188
+ function deriveSessionState(data) {
189
+ if (!data) {
190
+ return {
191
+ state: "NO_SESSION" /* NoSession */,
192
+ accessToken: null,
193
+ refreshToken: null,
194
+ idToken: null,
195
+ expiresAt: null,
196
+ user: null
197
+ };
198
+ }
199
+ return {
200
+ state: "AUTHENTICATED" /* Authenticated */,
201
+ accessToken: data.accessToken,
202
+ refreshToken: data.refreshToken,
203
+ idToken: data.idToken,
204
+ expiresAt: data.expiresAt,
205
+ user: null
206
+ // User is fetched separately when needed
207
+ };
208
+ }
209
+ function isTokenExpired(expiresAt) {
210
+ return Date.now() / 1e3 >= expiresAt - 30;
211
+ }
212
+
213
+ export {
214
+ resolveConfig,
215
+ fetchOIDCConfiguration,
216
+ decryptSession,
217
+ buildSessionCookie,
218
+ buildClearCookie,
219
+ buildPKCECookie,
220
+ decryptPKCECookie,
221
+ exchangeCode,
222
+ refreshAccessToken,
223
+ revokeToken,
224
+ deriveSessionState,
225
+ isTokenExpired
226
+ };
227
+ //# sourceMappingURL=chunk-MJD3XNUK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts","../src/oauth/discovery.ts","../src/session/cookie.ts","../src/oauth/token.ts","../src/session/state.ts"],"sourcesContent":["import { type AuthgearConfig, DEFAULT_SCOPES } from \"./types.js\";\n\nexport function resolveConfig(config: AuthgearConfig): Required<AuthgearConfig> {\n if (!config.endpoint) throw new Error(\"AuthgearConfig: endpoint is required\");\n if (!config.clientID) throw new Error(\"AuthgearConfig: clientID is required\");\n if (!config.redirectURI) throw new Error(\"AuthgearConfig: redirectURI is required\");\n if (!config.sessionSecret || config.sessionSecret.length < 32) {\n throw new Error(\"AuthgearConfig: sessionSecret must be at least 32 characters\");\n }\n\n return {\n endpoint: config.endpoint.replace(/\\/+$/, \"\"),\n clientID: config.clientID,\n clientSecret: config.clientSecret ?? \"\",\n redirectURI: config.redirectURI,\n postLogoutRedirectURI: config.postLogoutRedirectURI ?? \"/\",\n scopes: config.scopes ?? DEFAULT_SCOPES,\n sessionSecret: config.sessionSecret,\n cookieName: config.cookieName ?? \"authgear.session\",\n };\n}\n","import type { OIDCConfiguration } from \"../types.js\";\n\nconst cache = new Map<string, { config: OIDCConfiguration; fetchedAt: number }>();\nconst CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour\n\nexport async function fetchOIDCConfiguration(\n endpoint: string,\n): Promise<OIDCConfiguration> {\n const cached = cache.get(endpoint);\n if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {\n return cached.config;\n }\n\n const url = `${endpoint}/.well-known/openid-configuration`;\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`Failed to fetch OIDC configuration from ${url}: ${res.status}`);\n }\n\n const config = (await res.json()) as OIDCConfiguration;\n cache.set(endpoint, { config, fetchedAt: Date.now() });\n return config;\n}\n\n/** Clear cached OIDC configuration (useful for testing) */\nexport function clearOIDCCache(): void {\n cache.clear();\n}\n","import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from \"node:crypto\";\nimport type { SessionData } from \"../types.js\";\n\nconst ALGORITHM = \"aes-256-gcm\";\nconst IV_LENGTH = 12;\nconst AUTH_TAG_LENGTH = 16;\nconst KEY_LENGTH = 32;\nconst SALT = \"authgear-nextjs-session\";\n\nfunction deriveKey(secret: string): Buffer {\n return scryptSync(secret, SALT, KEY_LENGTH);\n}\n\nexport function encryptSession(data: SessionData, secret: string): string {\n const key = deriveKey(secret);\n const iv = randomBytes(IV_LENGTH);\n const cipher = createCipheriv(ALGORITHM, key, iv, { authTagLength: AUTH_TAG_LENGTH });\n\n const json = JSON.stringify(data);\n const encrypted = Buffer.concat([cipher.update(json, \"utf8\"), cipher.final()]);\n const authTag = cipher.getAuthTag();\n\n // Format: base64(iv + authTag + encrypted)\n return Buffer.concat([iv, authTag, encrypted]).toString(\"base64url\");\n}\n\nexport function decryptSession(encrypted: string, secret: string): SessionData | null {\n try {\n const key = deriveKey(secret);\n const buf = Buffer.from(encrypted, \"base64url\");\n\n if (buf.length < IV_LENGTH + AUTH_TAG_LENGTH) return null;\n\n const iv = buf.subarray(0, IV_LENGTH);\n const authTag = buf.subarray(IV_LENGTH, IV_LENGTH + AUTH_TAG_LENGTH);\n const ciphertext = buf.subarray(IV_LENGTH + AUTH_TAG_LENGTH);\n\n const decipher = createDecipheriv(ALGORITHM, key, iv, { authTagLength: AUTH_TAG_LENGTH });\n decipher.setAuthTag(authTag);\n\n const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n return JSON.parse(decrypted.toString(\"utf8\")) as SessionData;\n } catch {\n return null;\n }\n}\n\nexport interface CookieOptions {\n name: string;\n value: string;\n httpOnly?: boolean;\n secure?: boolean;\n sameSite?: \"lax\" | \"strict\" | \"none\";\n path?: string;\n maxAge?: number;\n}\n\nexport function buildSessionCookie(\n cookieName: string,\n data: SessionData,\n secret: string,\n): CookieOptions {\n return {\n name: cookieName,\n value: encryptSession(data, secret),\n httpOnly: true,\n secure: process.env.NODE_ENV === \"production\",\n sameSite: \"lax\",\n path: \"/\",\n maxAge: 30 * 24 * 60 * 60, // 30 days\n };\n}\n\nexport function buildClearCookie(cookieName: string): CookieOptions {\n return {\n name: cookieName,\n value: \"\",\n httpOnly: true,\n secure: process.env.NODE_ENV === \"production\",\n sameSite: \"lax\",\n path: \"/\",\n maxAge: 0,\n };\n}\n\nexport function buildPKCECookie(\n data: { codeVerifier: string; state: string; returnTo: string },\n secret: string,\n): CookieOptions {\n const key = deriveKey(secret);\n const iv = randomBytes(IV_LENGTH);\n const cipher = createCipheriv(ALGORITHM, key, iv, { authTagLength: AUTH_TAG_LENGTH });\n\n const json = JSON.stringify(data);\n const encrypted = Buffer.concat([cipher.update(json, \"utf8\"), cipher.final()]);\n const authTag = cipher.getAuthTag();\n\n return {\n name: \"authgear.pkce\",\n value: Buffer.concat([iv, authTag, encrypted]).toString(\"base64url\"),\n httpOnly: true,\n secure: process.env.NODE_ENV === \"production\",\n sameSite: \"lax\",\n path: \"/\",\n maxAge: 600, // 10 minutes\n };\n}\n\nexport function decryptPKCECookie(\n encrypted: string,\n secret: string,\n): { codeVerifier: string; state: string; returnTo: string } | null {\n try {\n const key = deriveKey(secret);\n const buf = Buffer.from(encrypted, \"base64url\");\n\n if (buf.length < IV_LENGTH + AUTH_TAG_LENGTH) return null;\n\n const iv = buf.subarray(0, IV_LENGTH);\n const authTag = buf.subarray(IV_LENGTH, IV_LENGTH + AUTH_TAG_LENGTH);\n const ciphertext = buf.subarray(IV_LENGTH + AUTH_TAG_LENGTH);\n\n const decipher = createDecipheriv(ALGORITHM, key, iv, { authTagLength: AUTH_TAG_LENGTH });\n decipher.setAuthTag(authTag);\n\n const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n return JSON.parse(decrypted.toString(\"utf8\"));\n } catch {\n return null;\n }\n}\n","import type { OIDCConfiguration, TokenResponse, AppSessionTokenResponse } from \"../types.js\";\n\nexport interface ExchangeCodeParams {\n code: string;\n codeVerifier: string;\n clientID: string;\n clientSecret?: string;\n redirectURI: string;\n}\n\nexport interface RefreshTokenParams {\n refreshToken: string;\n clientID: string;\n clientSecret?: string;\n}\n\nexport async function exchangeCode(\n oidcConfig: OIDCConfiguration,\n params: ExchangeCodeParams,\n): Promise<TokenResponse> {\n const body = new URLSearchParams({\n grant_type: \"authorization_code\",\n code: params.code,\n code_verifier: params.codeVerifier,\n client_id: params.clientID,\n redirect_uri: params.redirectURI,\n });\n if (params.clientSecret) {\n body.set(\"client_secret\", params.clientSecret);\n }\n\n const res = await fetch(oidcConfig.token_endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n\n if (!res.ok) {\n const error = await res.text();\n throw new Error(`Token exchange failed (${res.status}): ${error}`);\n }\n\n return res.json() as Promise<TokenResponse>;\n}\n\nexport async function refreshAccessToken(\n oidcConfig: OIDCConfiguration,\n params: RefreshTokenParams,\n): Promise<TokenResponse> {\n const body = new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: params.refreshToken,\n client_id: params.clientID,\n });\n if (params.clientSecret) {\n body.set(\"client_secret\", params.clientSecret);\n }\n\n const res = await fetch(oidcConfig.token_endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n\n if (!res.ok) {\n const error = await res.text();\n throw new Error(`Token refresh failed (${res.status}): ${error}`);\n }\n\n return res.json() as Promise<TokenResponse>;\n}\n\nexport async function getAppSessionToken(\n endpoint: string,\n refreshToken: string,\n): Promise<AppSessionTokenResponse> {\n const res = await fetch(`${endpoint}/oauth2/app_session_token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refresh_token: refreshToken }),\n });\n\n if (!res.ok) {\n const error = await res.text();\n throw new Error(`Failed to get app session token (${res.status}): ${error}`);\n }\n\n return res.json() as Promise<AppSessionTokenResponse>;\n}\n\nexport async function revokeToken(\n oidcConfig: OIDCConfiguration,\n token: string,\n): Promise<void> {\n await fetch(oidcConfig.revocation_endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({ token }).toString(),\n });\n}\n","import { SessionState, type SessionData, type Session } from \"../types.js\";\n\nexport function deriveSessionState(data: SessionData | null): Session {\n if (!data) {\n return {\n state: SessionState.NoSession,\n accessToken: null,\n refreshToken: null,\n idToken: null,\n expiresAt: null,\n user: null,\n };\n }\n\n return {\n state: SessionState.Authenticated,\n accessToken: data.accessToken,\n refreshToken: data.refreshToken,\n idToken: data.idToken,\n expiresAt: data.expiresAt,\n user: null, // User is fetched separately when needed\n };\n}\n\nexport function isTokenExpired(expiresAt: number): boolean {\n // Consider expired 30 seconds early for safety margin\n return Date.now() / 1000 >= expiresAt - 30;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,23 @@
1
+ // src/types.ts
2
+ var Page = /* @__PURE__ */ ((Page2) => {
3
+ Page2["Settings"] = "/settings";
4
+ return Page2;
5
+ })(Page || {});
6
+ var DEFAULT_SCOPES = [
7
+ "openid",
8
+ "offline_access",
9
+ "https://authgear.com/scopes/full-userinfo"
10
+ ];
11
+ var SessionState = /* @__PURE__ */ ((SessionState2) => {
12
+ SessionState2["Unknown"] = "UNKNOWN";
13
+ SessionState2["NoSession"] = "NO_SESSION";
14
+ SessionState2["Authenticated"] = "AUTHENTICATED";
15
+ return SessionState2;
16
+ })(SessionState || {});
17
+
18
+ export {
19
+ Page,
20
+ DEFAULT_SCOPES,
21
+ SessionState
22
+ };
23
+ //# sourceMappingURL=chunk-UY6NEM2T.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["export interface AuthgearConfig {\n /** Authgear endpoint, e.g. \"https://myapp.authgear.cloud\" */\n endpoint: string;\n /** OAuth client ID */\n clientID: string;\n /** OAuth client secret (for confidential server-side clients) */\n clientSecret?: string;\n /** Redirect URI for OAuth callback, e.g. \"http://localhost:3000/api/auth/callback\" */\n redirectURI: string;\n /** Where to redirect after logout */\n postLogoutRedirectURI?: string;\n /** OAuth scopes. Defaults to [\"openid\", \"offline_access\", \"https://authgear.com/scopes/full-userinfo\"] */\n scopes?: string[];\n /** Secret key for encrypting session cookie (min 32 chars) */\n sessionSecret: string;\n /** Session cookie name. Defaults to \"authgear.session\" */\n cookieName?: string;\n}\n\n/**\n * Pages that can be opened via open().\n */\nexport enum Page {\n Settings = \"/settings\",\n}\n\nexport const DEFAULT_SCOPES = [\n \"openid\",\n \"offline_access\",\n \"https://authgear.com/scopes/full-userinfo\",\n];\n\nexport enum SessionState {\n Unknown = \"UNKNOWN\",\n NoSession = \"NO_SESSION\",\n Authenticated = \"AUTHENTICATED\",\n}\n\nexport interface SessionData {\n accessToken: string;\n refreshToken: string | null;\n idToken: string | null;\n expiresAt: number;\n}\n\nexport interface Session {\n state: SessionState;\n accessToken: string | null;\n refreshToken: string | null;\n idToken: string | null;\n expiresAt: number | null;\n user: UserInfo | null;\n}\n\nexport interface UserInfo {\n sub: string;\n email?: string;\n emailVerified?: boolean;\n phoneNumber?: string;\n phoneNumberVerified?: boolean;\n preferredUsername?: string;\n givenName?: string;\n familyName?: string;\n name?: string;\n picture?: string;\n roles?: string[];\n isAnonymous?: boolean;\n isVerified?: boolean;\n canReauthenticate?: boolean;\n customAttributes?: Record<string, unknown>;\n raw: Record<string, unknown>;\n}\n\nexport interface JWTPayload {\n sub: string;\n iss: string;\n aud: string | string[];\n exp: number;\n iat: number;\n jti?: string;\n client_id?: string;\n \"https://authgear.com/claims/user/is_anonymous\"?: boolean;\n \"https://authgear.com/claims/user/is_verified\"?: boolean;\n \"https://authgear.com/claims/user/can_reauthenticate\"?: boolean;\n \"https://authgear.com/claims/user/roles\"?: string[];\n [key: string]: unknown;\n}\n\nexport interface TokenResponse {\n access_token: string;\n token_type: string;\n expires_in: number;\n refresh_token?: string;\n id_token?: string;\n}\n\nexport interface AppSessionTokenResponse {\n app_session_token: string;\n expire_at: string;\n}\n\nexport interface OIDCConfiguration {\n authorization_endpoint: string;\n token_endpoint: string;\n userinfo_endpoint: string;\n revocation_endpoint: string;\n end_session_endpoint: string;\n jwks_uri: string;\n issuer: string;\n}\n"],"mappings":";AAsBO,IAAK,OAAL,kBAAKA,UAAL;AACL,EAAAA,MAAA,cAAW;AADD,SAAAA;AAAA,GAAA;AAIL,IAAM,iBAAiB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAK,eAAL,kBAAKC,kBAAL;AACL,EAAAA,cAAA,aAAU;AACV,EAAAA,cAAA,eAAY;AACZ,EAAAA,cAAA,mBAAgB;AAHN,SAAAA;AAAA,GAAA;","names":["Page","SessionState"]}