@userbox/react 1.0.0-alpha.0 → 1.0.0-alpha.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/CHANGELOG.md +10 -0
- package/dist/nextjs.d.ts +1 -1
- package/dist/nextjs.js +2 -2
- package/dist/nextjs.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,16 @@ All notable changes to `@userbox/react` are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
7
|
|
|
8
|
+
## [1.0.0-alpha.1] — 2026-11-02
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- `@userbox/react/nextjs` now loads in plain Node ESM. It imports
|
|
12
|
+
`next/server.js` and `next/headers.js` instead of the extensionless
|
|
13
|
+
`next/server` and `next/headers`; `next` has no `exports` map, so the
|
|
14
|
+
extensionless imports failed with `ERR_MODULE_NOT_FOUND`, and TypeScript
|
|
15
|
+
reported TS2307 under `moduleResolution: nodenext` without `skipLibCheck`.
|
|
16
|
+
Next.js apps were not affected: the Next bundler resolves both forms.
|
|
17
|
+
|
|
8
18
|
## [1.0.0-alpha.0] — 2026-05-18
|
|
9
19
|
|
|
10
20
|
Initial alpha. Public surface frozen for the V1 scope.
|
package/dist/nextjs.d.ts
CHANGED
package/dist/nextjs.js
CHANGED
package/dist/nextjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/errors.ts","../src/core/http.ts","../src/nextjs/middleware.ts","../src/core/token.ts","../src/nextjs/server.ts"],"names":["headers","response"],"mappings":"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","file":"nextjs.js","sourcesContent":["/**\n * Userbox error tagged-union. Used by every layer of the SDK as the single\n * error shape callers may inspect. Tokens (access / refresh) MUST NEVER appear\n * in any `message` produced by these constructors — security invariant S-2.\n */\n\nexport type MisconfiguredField =\n | \"tenantSlug\"\n | \"baseUrl\"\n | \"tokenStorage\"\n | \"refreshUrl\"\n | \"callbackUrl\";\n\nexport type UserboxError =\n | {\n kind: \"missing_credentials\";\n message: string;\n requestId?: string;\n }\n | {\n kind: \"auth_failed\";\n message: string;\n httpStatus: number;\n code: string;\n requestId?: string;\n }\n | {\n kind: \"refresh_failed\";\n message: string;\n httpStatus: number;\n code: string;\n requestId?: string;\n }\n | {\n kind: \"permission_fetch_failed\";\n message: string;\n httpStatus: number;\n code: string;\n workspaceId: string;\n requestId?: string;\n }\n | { kind: \"network\"; message: string }\n | { kind: \"misconfigured\"; message: string; field: MisconfiguredField };\n\nconst ERROR_KINDS: ReadonlySet<string> = new Set([\n \"missing_credentials\",\n \"auth_failed\",\n \"refresh_failed\",\n \"permission_fetch_failed\",\n \"network\",\n \"misconfigured\",\n]);\n\n/** Type guard verifying a value is a `UserboxError`. */\nexport function isUserboxError(value: unknown): value is UserboxError {\n if (typeof value !== \"object\" || value === null) return false;\n const candidate = value as { kind?: unknown; message?: unknown };\n return (\n typeof candidate.kind === \"string\" &&\n ERROR_KINDS.has(candidate.kind) &&\n typeof candidate.message === \"string\"\n );\n}\n\nexport function missingCredentials(message: string, requestId?: string): UserboxError {\n return requestId\n ? { kind: \"missing_credentials\", message, requestId }\n : { kind: \"missing_credentials\", message };\n}\n\nexport function authFailed(\n message: string,\n httpStatus: number,\n code: string,\n requestId?: string,\n): UserboxError {\n return requestId\n ? { kind: \"auth_failed\", message, httpStatus, code, requestId }\n : { kind: \"auth_failed\", message, httpStatus, code };\n}\n\nexport function refreshFailed(\n message: string,\n httpStatus: number,\n code: string,\n requestId?: string,\n): UserboxError {\n return requestId\n ? { kind: \"refresh_failed\", message, httpStatus, code, requestId }\n : { kind: \"refresh_failed\", message, httpStatus, code };\n}\n\nexport function permissionFetchFailed(\n message: string,\n httpStatus: number,\n code: string,\n workspaceId: string,\n requestId?: string,\n): UserboxError {\n return requestId\n ? {\n kind: \"permission_fetch_failed\",\n message,\n httpStatus,\n code,\n workspaceId,\n requestId,\n }\n : { kind: \"permission_fetch_failed\", message, httpStatus, code, workspaceId };\n}\n\nexport function networkError(message: string): UserboxError {\n return { kind: \"network\", message };\n}\n\nexport function misconfigured(field: MisconfiguredField, message: string): UserboxError {\n return { kind: \"misconfigured\", message, field };\n}\n","import {\n authFailed,\n networkError,\n refreshFailed,\n permissionFetchFailed,\n type UserboxError,\n} from \"./errors\";\n\nexport type HttpRequestInput = {\n url: string;\n method?: \"GET\" | \"POST\" | \"DELETE\" | \"PUT\" | \"PATCH\";\n tenantSlug: string;\n accessToken?: string | null;\n body?: unknown;\n headers?: Record<string, string>;\n credentials?: RequestCredentials;\n signal?: AbortSignal;\n /**\n * Maps a non-2xx response to the right `UserboxError` kind. Each caller\n * names its own context (refresh / permissions / etc.) so the error surface\n * stays meaningful.\n */\n errorKind: \"auth\" | \"refresh\" | \"permissions\";\n workspaceId?: string;\n};\n\nexport type HttpResponse<T> =\n | { ok: true; data: T; requestId?: string }\n | { ok: false; error: UserboxError };\n\ntype ServerErrorShape = {\n code?: unknown;\n error?: unknown;\n};\n\nexport async function request<T>(input: HttpRequestInput): Promise<HttpResponse<T>> {\n const headers: Record<string, string> = {\n \"X-Tenant-ID\": input.tenantSlug,\n Accept: \"application/json\",\n ...input.headers,\n };\n if (input.accessToken) {\n headers.Authorization = `Bearer ${input.accessToken}`;\n }\n const init: RequestInit = {\n method: input.method ?? \"GET\",\n headers,\n };\n if (input.body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n init.body = JSON.stringify(input.body);\n }\n if (input.credentials !== undefined) {\n init.credentials = input.credentials;\n }\n if (input.signal) init.signal = input.signal;\n\n let response: Response;\n try {\n response = await fetch(input.url, init);\n } catch (err) {\n return {\n ok: false,\n error: networkError(humaniseNetworkError(err)),\n };\n }\n\n const requestId = response.headers.get(\"X-Request-ID\") ?? undefined;\n\n if (response.status === 204) {\n return { ok: true, data: undefined as T, requestId };\n }\n\n let parsed: unknown = null;\n const text = await response.text();\n if (text.length > 0) {\n try {\n parsed = JSON.parse(text);\n } catch {\n parsed = null;\n }\n }\n\n if (response.ok) {\n return { ok: true, data: parsed as T, requestId };\n }\n\n const shape = (parsed ?? {}) as ServerErrorShape;\n const code = typeof shape.code === \"string\" ? shape.code : \"UNKNOWN\";\n const message =\n typeof shape.error === \"string\"\n ? shape.error\n : `HTTP ${response.status}`;\n const error = mapServerError(input, response.status, code, message, requestId);\n return { ok: false, error };\n}\n\nfunction mapServerError(\n input: HttpRequestInput,\n status: number,\n code: string,\n message: string,\n requestId?: string,\n): UserboxError {\n switch (input.errorKind) {\n case \"refresh\":\n return refreshFailed(message, status, code, requestId);\n case \"permissions\":\n return permissionFetchFailed(\n message,\n status,\n code,\n input.workspaceId ?? \"\",\n requestId,\n );\n case \"auth\":\n default:\n return authFailed(message, status, code, requestId);\n }\n}\n\nfunction humaniseNetworkError(err: unknown): string {\n if (err instanceof DOMException && err.name === \"AbortError\") {\n return \"Request aborted\";\n }\n if (err instanceof Error) return err.message || \"Network error\";\n return \"Network error\";\n}\n","import { NextResponse, type NextRequest } from \"next/server\";\nimport { request } from \"../core/http\";\nimport {\n authFailed,\n networkError,\n refreshFailed,\n type UserboxError,\n} from \"../core/errors\";\n\nexport type MiddlewareConfig = {\n tenantSlug: string;\n baseUrl: string;\n refreshCookieName?: string;\n accessTokenHeader?: string;\n cookieDomain?: string;\n cookieSecure?: boolean;\n cookieSameSite?: \"lax\" | \"strict\" | \"none\";\n matcher?: string[];\n onError?: (err: UserboxError, req: NextRequest) => void;\n};\n\nconst DEFAULT_REFRESH_COOKIE_NAME = \"ub_refresh\";\nconst DEFAULT_ACCESS_TOKEN_HEADER = \"x-userbox-access-token\";\nconst PERMANENT_STATUSES: ReadonlySet<number> = new Set([400, 401, 403]);\n\nlet warnedNoCookie = false;\n\ntype RefreshHttpResponse = {\n access_token?: unknown;\n refresh_token?: unknown;\n expires_in?: unknown;\n refresh_expires_in?: unknown;\n};\n\nexport function userboxMiddleware(\n config: MiddlewareConfig,\n): (req: NextRequest) => Promise<NextResponse> {\n const refreshCookieName = config.refreshCookieName ?? DEFAULT_REFRESH_COOKIE_NAME;\n const accessTokenHeader = config.accessTokenHeader ?? DEFAULT_ACCESS_TOKEN_HEADER;\n const cookieSecure = config.cookieSecure ?? process.env.NODE_ENV !== \"development\";\n const sameSite = config.cookieSameSite ?? \"lax\";\n\n return async function middleware(req: NextRequest): Promise<NextResponse> {\n const cookie = req.cookies.get(refreshCookieName);\n if (!cookie || !cookie.value) {\n if (!warnedNoCookie) {\n warnedNoCookie = true;\n // Warn on storage-mode mismatch.\n console.warn(\n \"[@userbox/react] userboxMiddleware: no refresh cookie present on this request. \" +\n \"If the app uses tokenStorage: 'memory', the middleware should not be installed.\",\n );\n }\n return NextResponse.next();\n }\n\n const res = await request<RefreshHttpResponse>({\n url: `${config.baseUrl}/v1/auth/refresh`,\n method: \"POST\",\n tenantSlug: config.tenantSlug,\n body: { refresh_token: cookie.value },\n errorKind: \"refresh\",\n });\n\n if (!res.ok) {\n const err = res.error;\n const isPermanent =\n (err.kind === \"refresh_failed\" || err.kind === \"auth_failed\") &&\n PERMANENT_STATUSES.has(err.httpStatus);\n const response = NextResponse.next();\n if (isPermanent) {\n response.cookies.delete(refreshCookieName);\n config.onError?.(err, req);\n } else {\n // Transient — preserve the cookie; surface error; let next request retry.\n config.onError?.(err, req);\n }\n return response;\n }\n\n const data = res.data;\n const accessToken = typeof data.access_token === \"string\" ? data.access_token : \"\";\n const newRefresh = typeof data.refresh_token === \"string\" ? data.refresh_token : \"\";\n const expiresIn = typeof data.expires_in === \"number\" ? data.expires_in : 0;\n const refreshExpiresIn =\n typeof data.refresh_expires_in === \"number\"\n ? data.refresh_expires_in\n : expiresIn;\n if (!accessToken || !newRefresh || !expiresIn) {\n const response = NextResponse.next();\n config.onError?.(\n networkError(\"Refresh response missing fields\"),\n req,\n );\n return response;\n }\n\n // Forward the access token via a request header. We mutate the incoming\n // headers in a new NextResponse since req.headers is readable but tunnels\n // must be set on the response's request rewrite.\n const requestHeaders = new Headers(req.headers);\n requestHeaders.set(accessTokenHeader, accessToken);\n\n const response = NextResponse.next({\n request: { headers: requestHeaders },\n });\n\n response.cookies.set(refreshCookieName, newRefresh, {\n httpOnly: true,\n secure: cookieSecure,\n sameSite,\n ...(config.cookieDomain ? { domain: config.cookieDomain } : {}),\n maxAge: refreshExpiresIn,\n path: \"/\",\n });\n\n // refreshFailed reference suppression\n void refreshFailed; void authFailed;\n return response;\n };\n}\n","import { authFailed, type UserboxError } from \"./errors\";\n\nexport type JwtClaims = {\n sub: string;\n tid: string;\n exp: number;\n jti?: string;\n};\n\nfunction base64UrlDecode(input: string): string {\n let s = input.replace(/-/g, \"+\").replace(/_/g, \"/\");\n while (s.length % 4 !== 0) s += \"=\";\n if (typeof atob === \"function\") return atob(s);\n return Buffer.from(s, \"base64\").toString(\"binary\");\n}\n\n/**\n * Decode JWT claims without signature verification. The server is the only\n * authority on token validity; the SDK uses\n * `exp` only to drive its proactive-refresh timer.\n */\nexport function decodeJwtClaims(token: string): JwtClaims {\n const parts = token.split(\".\");\n if (parts.length !== 3) {\n throw asAuthFailed(\"Malformed JWT\");\n }\n const payload = parts[1];\n if (!payload) throw asAuthFailed(\"Malformed JWT payload\");\n\n let json: string;\n try {\n json = base64UrlDecode(payload);\n } catch {\n throw asAuthFailed(\"Malformed JWT payload\");\n }\n\n let obj: unknown;\n try {\n obj = JSON.parse(json);\n } catch {\n throw asAuthFailed(\"Malformed JWT payload\");\n }\n\n if (typeof obj !== \"object\" || obj === null) {\n throw asAuthFailed(\"Malformed JWT payload\");\n }\n const claims = obj as Record<string, unknown>;\n const sub = typeof claims.sub === \"string\" ? claims.sub : null;\n const tid = typeof claims.tid === \"string\" ? claims.tid : null;\n const exp = typeof claims.exp === \"number\" ? claims.exp : null;\n const jti = typeof claims.jti === \"string\" ? claims.jti : undefined;\n if (!sub || !tid || exp === null) {\n throw asAuthFailed(\"JWT missing required claims (sub/tid/exp)\");\n }\n return jti ? { sub, tid, exp, jti } : { sub, tid, exp };\n}\n\nfunction asAuthFailed(message: string): UserboxError {\n return authFailed(message, 401, \"MALFORMED_JWT\");\n}\n","import { headers } from \"next/headers\";\nimport { decodeJwtClaims } from \"../core/token\";\nimport type { Session } from \"../core/refresh-engine\";\n\n/**\n * Reads the access token forwarded by `userboxMiddleware` from the request\n * headers and returns the full session. Returns `null` if the header is absent\n * (no signed-in user for this request).\n *\n * **SECURITY**: the returned `ServerSession` contains the bearer `accessToken`.\n * This object MUST NOT be passed as a prop to a Client Component — Next.js\n * will serialise the token into the client bundle and defeat the\n * memory-only-storage guarantee. Pass `session.user` instead.\n */\nexport async function getSession(): Promise<Session | null> {\n const hdrs = await headers();\n const accessTokenHeader =\n hdrs.get(\"x-userbox-access-token\") ?? hdrs.get(\"X-Userbox-Access-Token\");\n if (!accessTokenHeader) return null;\n\n let claims;\n try {\n claims = decodeJwtClaims(accessTokenHeader);\n } catch {\n return null;\n }\n\n return {\n accessToken: accessTokenHeader,\n accessTokenExpiresAt: claims.exp * 1000,\n refreshExpiresAt: 0,\n user: {\n id: claims.sub,\n tenantId: claims.tid,\n email: null,\n fullName: null,\n },\n };\n}\n\nexport type { Session as ServerSession } from \"../core/refresh-engine\";\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/errors.ts","../src/core/http.ts","../src/nextjs/middleware.ts","../src/core/token.ts","../src/nextjs/server.ts"],"names":["headers","response"],"mappings":"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","file":"nextjs.js","sourcesContent":["/**\n * Userbox error tagged-union. Used by every layer of the SDK as the single\n * error shape callers may inspect. Tokens (access / refresh) MUST NEVER appear\n * in any `message` produced by these constructors — security invariant S-2.\n */\n\nexport type MisconfiguredField =\n | \"tenantSlug\"\n | \"baseUrl\"\n | \"tokenStorage\"\n | \"refreshUrl\"\n | \"callbackUrl\";\n\nexport type UserboxError =\n | {\n kind: \"missing_credentials\";\n message: string;\n requestId?: string;\n }\n | {\n kind: \"auth_failed\";\n message: string;\n httpStatus: number;\n code: string;\n requestId?: string;\n }\n | {\n kind: \"refresh_failed\";\n message: string;\n httpStatus: number;\n code: string;\n requestId?: string;\n }\n | {\n kind: \"permission_fetch_failed\";\n message: string;\n httpStatus: number;\n code: string;\n workspaceId: string;\n requestId?: string;\n }\n | { kind: \"network\"; message: string }\n | { kind: \"misconfigured\"; message: string; field: MisconfiguredField };\n\nconst ERROR_KINDS: ReadonlySet<string> = new Set([\n \"missing_credentials\",\n \"auth_failed\",\n \"refresh_failed\",\n \"permission_fetch_failed\",\n \"network\",\n \"misconfigured\",\n]);\n\n/** Type guard verifying a value is a `UserboxError`. */\nexport function isUserboxError(value: unknown): value is UserboxError {\n if (typeof value !== \"object\" || value === null) return false;\n const candidate = value as { kind?: unknown; message?: unknown };\n return (\n typeof candidate.kind === \"string\" &&\n ERROR_KINDS.has(candidate.kind) &&\n typeof candidate.message === \"string\"\n );\n}\n\nexport function missingCredentials(message: string, requestId?: string): UserboxError {\n return requestId\n ? { kind: \"missing_credentials\", message, requestId }\n : { kind: \"missing_credentials\", message };\n}\n\nexport function authFailed(\n message: string,\n httpStatus: number,\n code: string,\n requestId?: string,\n): UserboxError {\n return requestId\n ? { kind: \"auth_failed\", message, httpStatus, code, requestId }\n : { kind: \"auth_failed\", message, httpStatus, code };\n}\n\nexport function refreshFailed(\n message: string,\n httpStatus: number,\n code: string,\n requestId?: string,\n): UserboxError {\n return requestId\n ? { kind: \"refresh_failed\", message, httpStatus, code, requestId }\n : { kind: \"refresh_failed\", message, httpStatus, code };\n}\n\nexport function permissionFetchFailed(\n message: string,\n httpStatus: number,\n code: string,\n workspaceId: string,\n requestId?: string,\n): UserboxError {\n return requestId\n ? {\n kind: \"permission_fetch_failed\",\n message,\n httpStatus,\n code,\n workspaceId,\n requestId,\n }\n : { kind: \"permission_fetch_failed\", message, httpStatus, code, workspaceId };\n}\n\nexport function networkError(message: string): UserboxError {\n return { kind: \"network\", message };\n}\n\nexport function misconfigured(field: MisconfiguredField, message: string): UserboxError {\n return { kind: \"misconfigured\", message, field };\n}\n","import {\n authFailed,\n networkError,\n refreshFailed,\n permissionFetchFailed,\n type UserboxError,\n} from \"./errors\";\n\nexport type HttpRequestInput = {\n url: string;\n method?: \"GET\" | \"POST\" | \"DELETE\" | \"PUT\" | \"PATCH\";\n tenantSlug: string;\n accessToken?: string | null;\n body?: unknown;\n headers?: Record<string, string>;\n credentials?: RequestCredentials;\n signal?: AbortSignal;\n /**\n * Maps a non-2xx response to the right `UserboxError` kind. Each caller\n * names its own context (refresh / permissions / etc.) so the error surface\n * stays meaningful.\n */\n errorKind: \"auth\" | \"refresh\" | \"permissions\";\n workspaceId?: string;\n};\n\nexport type HttpResponse<T> =\n | { ok: true; data: T; requestId?: string }\n | { ok: false; error: UserboxError };\n\ntype ServerErrorShape = {\n code?: unknown;\n error?: unknown;\n};\n\nexport async function request<T>(input: HttpRequestInput): Promise<HttpResponse<T>> {\n const headers: Record<string, string> = {\n \"X-Tenant-ID\": input.tenantSlug,\n Accept: \"application/json\",\n ...input.headers,\n };\n if (input.accessToken) {\n headers.Authorization = `Bearer ${input.accessToken}`;\n }\n const init: RequestInit = {\n method: input.method ?? \"GET\",\n headers,\n };\n if (input.body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n init.body = JSON.stringify(input.body);\n }\n if (input.credentials !== undefined) {\n init.credentials = input.credentials;\n }\n if (input.signal) init.signal = input.signal;\n\n let response: Response;\n try {\n response = await fetch(input.url, init);\n } catch (err) {\n return {\n ok: false,\n error: networkError(humaniseNetworkError(err)),\n };\n }\n\n const requestId = response.headers.get(\"X-Request-ID\") ?? undefined;\n\n if (response.status === 204) {\n return { ok: true, data: undefined as T, requestId };\n }\n\n let parsed: unknown = null;\n const text = await response.text();\n if (text.length > 0) {\n try {\n parsed = JSON.parse(text);\n } catch {\n parsed = null;\n }\n }\n\n if (response.ok) {\n return { ok: true, data: parsed as T, requestId };\n }\n\n const shape = (parsed ?? {}) as ServerErrorShape;\n const code = typeof shape.code === \"string\" ? shape.code : \"UNKNOWN\";\n const message =\n typeof shape.error === \"string\"\n ? shape.error\n : `HTTP ${response.status}`;\n const error = mapServerError(input, response.status, code, message, requestId);\n return { ok: false, error };\n}\n\nfunction mapServerError(\n input: HttpRequestInput,\n status: number,\n code: string,\n message: string,\n requestId?: string,\n): UserboxError {\n switch (input.errorKind) {\n case \"refresh\":\n return refreshFailed(message, status, code, requestId);\n case \"permissions\":\n return permissionFetchFailed(\n message,\n status,\n code,\n input.workspaceId ?? \"\",\n requestId,\n );\n case \"auth\":\n default:\n return authFailed(message, status, code, requestId);\n }\n}\n\nfunction humaniseNetworkError(err: unknown): string {\n if (err instanceof DOMException && err.name === \"AbortError\") {\n return \"Request aborted\";\n }\n if (err instanceof Error) return err.message || \"Network error\";\n return \"Network error\";\n}\n","import { NextResponse, type NextRequest } from \"next/server.js\";\nimport { request } from \"../core/http\";\nimport {\n authFailed,\n networkError,\n refreshFailed,\n type UserboxError,\n} from \"../core/errors\";\n\nexport type MiddlewareConfig = {\n tenantSlug: string;\n baseUrl: string;\n refreshCookieName?: string;\n accessTokenHeader?: string;\n cookieDomain?: string;\n cookieSecure?: boolean;\n cookieSameSite?: \"lax\" | \"strict\" | \"none\";\n matcher?: string[];\n onError?: (err: UserboxError, req: NextRequest) => void;\n};\n\nconst DEFAULT_REFRESH_COOKIE_NAME = \"ub_refresh\";\nconst DEFAULT_ACCESS_TOKEN_HEADER = \"x-userbox-access-token\";\nconst PERMANENT_STATUSES: ReadonlySet<number> = new Set([400, 401, 403]);\n\nlet warnedNoCookie = false;\n\ntype RefreshHttpResponse = {\n access_token?: unknown;\n refresh_token?: unknown;\n expires_in?: unknown;\n refresh_expires_in?: unknown;\n};\n\nexport function userboxMiddleware(\n config: MiddlewareConfig,\n): (req: NextRequest) => Promise<NextResponse> {\n const refreshCookieName = config.refreshCookieName ?? DEFAULT_REFRESH_COOKIE_NAME;\n const accessTokenHeader = config.accessTokenHeader ?? DEFAULT_ACCESS_TOKEN_HEADER;\n const cookieSecure = config.cookieSecure ?? process.env.NODE_ENV !== \"development\";\n const sameSite = config.cookieSameSite ?? \"lax\";\n\n return async function middleware(req: NextRequest): Promise<NextResponse> {\n const cookie = req.cookies.get(refreshCookieName);\n if (!cookie || !cookie.value) {\n if (!warnedNoCookie) {\n warnedNoCookie = true;\n // Warn on storage-mode mismatch.\n console.warn(\n \"[@userbox/react] userboxMiddleware: no refresh cookie present on this request. \" +\n \"If the app uses tokenStorage: 'memory', the middleware should not be installed.\",\n );\n }\n return NextResponse.next();\n }\n\n const res = await request<RefreshHttpResponse>({\n url: `${config.baseUrl}/v1/auth/refresh`,\n method: \"POST\",\n tenantSlug: config.tenantSlug,\n body: { refresh_token: cookie.value },\n errorKind: \"refresh\",\n });\n\n if (!res.ok) {\n const err = res.error;\n const isPermanent =\n (err.kind === \"refresh_failed\" || err.kind === \"auth_failed\") &&\n PERMANENT_STATUSES.has(err.httpStatus);\n const response = NextResponse.next();\n if (isPermanent) {\n response.cookies.delete(refreshCookieName);\n config.onError?.(err, req);\n } else {\n // Transient — preserve the cookie; surface error; let next request retry.\n config.onError?.(err, req);\n }\n return response;\n }\n\n const data = res.data;\n const accessToken = typeof data.access_token === \"string\" ? data.access_token : \"\";\n const newRefresh = typeof data.refresh_token === \"string\" ? data.refresh_token : \"\";\n const expiresIn = typeof data.expires_in === \"number\" ? data.expires_in : 0;\n const refreshExpiresIn =\n typeof data.refresh_expires_in === \"number\"\n ? data.refresh_expires_in\n : expiresIn;\n if (!accessToken || !newRefresh || !expiresIn) {\n const response = NextResponse.next();\n config.onError?.(\n networkError(\"Refresh response missing fields\"),\n req,\n );\n return response;\n }\n\n // Forward the access token via a request header. We mutate the incoming\n // headers in a new NextResponse since req.headers is readable but tunnels\n // must be set on the response's request rewrite.\n const requestHeaders = new Headers(req.headers);\n requestHeaders.set(accessTokenHeader, accessToken);\n\n const response = NextResponse.next({\n request: { headers: requestHeaders },\n });\n\n response.cookies.set(refreshCookieName, newRefresh, {\n httpOnly: true,\n secure: cookieSecure,\n sameSite,\n ...(config.cookieDomain ? { domain: config.cookieDomain } : {}),\n maxAge: refreshExpiresIn,\n path: \"/\",\n });\n\n // refreshFailed reference suppression\n void refreshFailed; void authFailed;\n return response;\n };\n}\n","import { authFailed, type UserboxError } from \"./errors\";\n\nexport type JwtClaims = {\n sub: string;\n tid: string;\n exp: number;\n jti?: string;\n};\n\nfunction base64UrlDecode(input: string): string {\n let s = input.replace(/-/g, \"+\").replace(/_/g, \"/\");\n while (s.length % 4 !== 0) s += \"=\";\n if (typeof atob === \"function\") return atob(s);\n return Buffer.from(s, \"base64\").toString(\"binary\");\n}\n\n/**\n * Decode JWT claims without signature verification. The server is the only\n * authority on token validity; the SDK uses\n * `exp` only to drive its proactive-refresh timer.\n */\nexport function decodeJwtClaims(token: string): JwtClaims {\n const parts = token.split(\".\");\n if (parts.length !== 3) {\n throw asAuthFailed(\"Malformed JWT\");\n }\n const payload = parts[1];\n if (!payload) throw asAuthFailed(\"Malformed JWT payload\");\n\n let json: string;\n try {\n json = base64UrlDecode(payload);\n } catch {\n throw asAuthFailed(\"Malformed JWT payload\");\n }\n\n let obj: unknown;\n try {\n obj = JSON.parse(json);\n } catch {\n throw asAuthFailed(\"Malformed JWT payload\");\n }\n\n if (typeof obj !== \"object\" || obj === null) {\n throw asAuthFailed(\"Malformed JWT payload\");\n }\n const claims = obj as Record<string, unknown>;\n const sub = typeof claims.sub === \"string\" ? claims.sub : null;\n const tid = typeof claims.tid === \"string\" ? claims.tid : null;\n const exp = typeof claims.exp === \"number\" ? claims.exp : null;\n const jti = typeof claims.jti === \"string\" ? claims.jti : undefined;\n if (!sub || !tid || exp === null) {\n throw asAuthFailed(\"JWT missing required claims (sub/tid/exp)\");\n }\n return jti ? { sub, tid, exp, jti } : { sub, tid, exp };\n}\n\nfunction asAuthFailed(message: string): UserboxError {\n return authFailed(message, 401, \"MALFORMED_JWT\");\n}\n","import { headers } from \"next/headers.js\";\nimport { decodeJwtClaims } from \"../core/token\";\nimport type { Session } from \"../core/refresh-engine\";\n\n/**\n * Reads the access token forwarded by `userboxMiddleware` from the request\n * headers and returns the full session. Returns `null` if the header is absent\n * (no signed-in user for this request).\n *\n * **SECURITY**: the returned `ServerSession` contains the bearer `accessToken`.\n * This object MUST NOT be passed as a prop to a Client Component — Next.js\n * will serialise the token into the client bundle and defeat the\n * memory-only-storage guarantee. Pass `session.user` instead.\n */\nexport async function getSession(): Promise<Session | null> {\n const hdrs = await headers();\n const accessTokenHeader =\n hdrs.get(\"x-userbox-access-token\") ?? hdrs.get(\"X-Userbox-Access-Token\");\n if (!accessTokenHeader) return null;\n\n let claims;\n try {\n claims = decodeJwtClaims(accessTokenHeader);\n } catch {\n return null;\n }\n\n return {\n accessToken: accessTokenHeader,\n accessTokenExpiresAt: claims.exp * 1000,\n refreshExpiresAt: 0,\n user: {\n id: claims.sub,\n tenantId: claims.tid,\n email: null,\n fullName: null,\n },\n };\n}\n\nexport type { Session as ServerSession } from \"../core/refresh-engine\";\n"]}
|
package/package.json
CHANGED