@spawn-llc/auth 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/IDENTITY.md +5 -2
- package/README.md +23 -6
- package/dist/{chunk-ZIYU4K3F.js → chunk-ELKYJ3OA.js} +6 -1
- package/dist/config.d.ts +26 -1
- package/dist/config.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/nextjs/index.d.ts +58 -5
- package/dist/nextjs/index.js +13 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
**Thicken the package so apps need no local auth layer or copy-pasted wiring.** Everything the apps
|
|
6
|
+
were reaching around for now lives here, and the docs stop recommending the unsafe matcher.
|
|
7
|
+
|
|
8
|
+
- **`AUTH_MATCHER` + `authProxyConfig` (from `@spawn-llc/auth/config`).** The one hardened
|
|
9
|
+
proxy/middleware matcher, defined once instead of copy-pasted per app. It closes the "F1" bypass
|
|
10
|
+
where a dynamic API segment ending in an image extension (`PATCH /api/thing/{id}.png`) escaped the
|
|
11
|
+
gate. Use `export const config = authProxyConfig`. The README/IDENTITY examples previously showed a
|
|
12
|
+
matcher that excluded `/api` entirely and left that bypass open — fixed.
|
|
13
|
+
- **`safeAuthProxy({ onUnconfigured })` (from `@spawn-llc/auth/nextjs`).** Fails **closed** when the
|
|
14
|
+
WORKOS_* secrets are absent, delegating to an app-supplied fallback (redirect / 404 / next). Folds
|
|
15
|
+
the three different hand-rolled "unconfigured" branches (`admin`, `landing`, `sites`) into one
|
|
16
|
+
shared code path. `authProxy()` is unchanged.
|
|
17
|
+
- **`requireApiUser()` (from `@spawn-llc/auth/nextjs`).** The API-handler counterpart to
|
|
18
|
+
`requireUser()`: returns the `User`, or a `401` JSON `NextResponse` when signed out (never a
|
|
19
|
+
redirect, which a `fetch()` caller can't parse). Replaces the per-app `lib/api-auth.ts` wrappers.
|
|
20
|
+
- **`appPublicPaths(extra)` (from `@spawn-llc/auth/config`).** Shared defaults plus an app's in-code
|
|
21
|
+
public routes, so an app with app-specific public paths (a Slack webhook, a cron tick) no longer
|
|
22
|
+
needs a local config wrapper package.
|
|
23
|
+
- **Convention:** `proxy.ts` + `export default authProxy()` is canonical; use `middleware.ts` only
|
|
24
|
+
when genuinely wrapping the proxy (e.g. `safeAuthProxy`, host routing).
|
|
25
|
+
|
|
3
26
|
## 0.2.1
|
|
4
27
|
|
|
5
28
|
**Fix: the session readers now force dynamic rendering before any early return.**
|
package/IDENTITY.md
CHANGED
|
@@ -51,8 +51,11 @@ app → own /login /signup /verify /reset routes renderi
|
|
|
51
51
|
1. `pnpm add @spawn-llc/auth @spawn-llc/design-system`.
|
|
52
52
|
2. Env from the "Spawn" application: `WORKOS_API_KEY`, `WORKOS_CLIENT_ID`, `WORKOS_COOKIE_PASSWORD`,
|
|
53
53
|
`NEXT_PUBLIC_WORKOS_REDIRECT_URI=<app>/callback`; add that redirect URI in the WorkOS dashboard.
|
|
54
|
-
3. `proxy.ts` → `export default authProxy()
|
|
55
|
-
handleCallback()`.
|
|
54
|
+
3. `proxy.ts` → `export default authProxy()` + `export const config = authProxyConfig` (the shared
|
|
55
|
+
hardened matcher). `app/callback/route.ts` → `export const GET = handleCallback()`. If the app
|
|
56
|
+
must stay up on preview deploys with no secrets, use a `middleware.ts` wrapping
|
|
57
|
+
`safeAuthProxy({ onUnconfigured })` instead. Gate API handlers with `requireApiUser()` (401 JSON,
|
|
58
|
+
never a redirect); pages/layouts with `requireUser()`.
|
|
56
59
|
4. Build `/login`, `/signup`, `/verify`, `/reset` rendering the DS screens, wired to the headless
|
|
57
60
|
flows via `"use server"` actions.
|
|
58
61
|
5. Internal-only tool? Set `ALLOWED_EMAIL_DOMAINS=spawnpartners.com`.
|
package/README.md
CHANGED
|
@@ -23,19 +23,36 @@ internal tools), `AUTH_PUBLIC_PATHS`.
|
|
|
23
23
|
- **`@spawn-llc/auth`** — core, edge-safe: the `IdentityGateway` (orgs / members / roles / invites) +
|
|
24
24
|
`createIdentityGateway()`, domain types (`Role`, `Session`, `Member`, `Invite`), and policy
|
|
25
25
|
(`isWorkosConfigured`, `isAllowedEmail`, `isPublicPath`).
|
|
26
|
-
- **`@spawn-llc/auth/config`** — the edge-safe policy alone (import from middleware; no SDK)
|
|
26
|
+
- **`@spawn-llc/auth/config`** — the edge-safe policy alone (import from middleware; no SDK): the
|
|
27
|
+
gate + `isPublicPath` / `appPublicPaths` and the shared hardened matcher (`AUTH_MATCHER`,
|
|
28
|
+
`authProxyConfig`).
|
|
27
29
|
- **`@spawn-llc/auth/nextjs`** — the Next server surface: the session seam
|
|
28
|
-
(`currentUser` / `requireUser` / `session` / `signOut` / `switchOrganization`),
|
|
29
|
-
`handleCallback()`, and the headless flows
|
|
30
|
-
`
|
|
30
|
+
(`currentUser` / `requireUser` / `requireApiUser` / `session` / `signOut` / `switchOrganization`),
|
|
31
|
+
`authProxy()` / `safeAuthProxy()`, `handleCallback()`, and the headless flows
|
|
32
|
+
(`signInWithPassword`, `signUp`, `verifyEmail`, `requestPasswordReset`, `resetPassword`,
|
|
33
|
+
`startOAuth`).
|
|
31
34
|
|
|
32
35
|
## Wire an app (Next.js)
|
|
33
36
|
|
|
34
37
|
```ts
|
|
35
|
-
// proxy.ts (
|
|
38
|
+
// proxy.ts (refresh the session on every route; gate in-app via requireUser())
|
|
36
39
|
import { authProxy } from "@spawn-llc/auth/nextjs";
|
|
40
|
+
import { authProxyConfig } from "@spawn-llc/auth/config";
|
|
37
41
|
export default authProxy();
|
|
38
|
-
export const config =
|
|
42
|
+
export const config = authProxyConfig; // the one shared hardened matcher — don't hand-write it
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Need to fail closed when the WORKOS_* secrets are absent (a preview deploy)? Use a `middleware.ts`
|
|
46
|
+
that wraps the proxy with `safeAuthProxy({ onUnconfigured })` instead of a bare `proxy.ts`.
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
// app/(any)/api/route.ts — gate a route handler (401 JSON, never a redirect)
|
|
50
|
+
import { requireApiUser } from "@spawn-llc/auth/nextjs";
|
|
51
|
+
export async function GET() {
|
|
52
|
+
const user = await requireApiUser();
|
|
53
|
+
if (user instanceof Response) return user; // 401 when signed out
|
|
54
|
+
// ...use `user`
|
|
55
|
+
}
|
|
39
56
|
```
|
|
40
57
|
|
|
41
58
|
```ts
|
|
@@ -7,6 +7,11 @@ function publicPaths() {
|
|
|
7
7
|
function isPublicPath(pathname, paths = publicPaths()) {
|
|
8
8
|
return paths.some((p) => pathname === p || pathname.startsWith(`${p}/`));
|
|
9
9
|
}
|
|
10
|
+
function appPublicPaths(extra) {
|
|
11
|
+
return [...publicPaths(), ...extra];
|
|
12
|
+
}
|
|
13
|
+
var AUTH_MATCHER = "/((?!_next/static|_next/image|favicon\\.ico|(?!(?:.*/)?api/).*\\.(?:svg|png|jpg|jpeg|gif|webp|ico)$).*)";
|
|
14
|
+
var authProxyConfig = { matcher: [AUTH_MATCHER] };
|
|
10
15
|
function isWorkosConfigured() {
|
|
11
16
|
return Boolean(
|
|
12
17
|
process.env.WORKOS_API_KEY && (process.env.WORKOS_CLIENT_ID || process.env.NEXT_PUBLIC_WORKOS_CLIENT_ID) && process.env.WORKOS_COOKIE_PASSWORD
|
|
@@ -42,4 +47,4 @@ function workosClientId() {
|
|
|
42
47
|
return id;
|
|
43
48
|
}
|
|
44
49
|
|
|
45
|
-
export { DEFAULT_PUBLIC_PATHS, allowedEmailDomains, assertEmailDomainGate, isAllowedEmail, isPublicPath, isWorkosConfigured, publicPaths, requiresEmailDomainGate, workosClientId };
|
|
50
|
+
export { AUTH_MATCHER, DEFAULT_PUBLIC_PATHS, allowedEmailDomains, appPublicPaths, assertEmailDomainGate, authProxyConfig, isAllowedEmail, isPublicPath, isWorkosConfigured, publicPaths, requiresEmailDomainGate, workosClientId };
|
package/dist/config.d.ts
CHANGED
|
@@ -8,6 +8,31 @@ declare const DEFAULT_PUBLIC_PATHS: readonly ["/login", "/signup", "/verify", "/
|
|
|
8
8
|
/** The public paths for this app: the defaults plus anything in `AUTH_PUBLIC_PATHS` (comma-sep). */
|
|
9
9
|
declare function publicPaths(): string[];
|
|
10
10
|
declare function isPublicPath(pathname: string, paths?: string[]): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* The public paths for an app that declares extra ones IN CODE (not via `AUTH_PUBLIC_PATHS`):
|
|
13
|
+
* the shared defaults plus the caller's list. Lets an app keep app-specific public routes (a
|
|
14
|
+
* Slack webhook, a cron tick, an unsubscribe link) alongside the login-flow defaults without a
|
|
15
|
+
* local wrapper package. Pair with `isPublicPath(pathname, appPublicPaths([...]))`.
|
|
16
|
+
*/
|
|
17
|
+
declare function appPublicPaths(extra: string[]): string[];
|
|
18
|
+
/**
|
|
19
|
+
* The canonical proxy/middleware matcher — the ONE hardened regex every app should use, so the
|
|
20
|
+
* pattern is defined once here instead of copy-pasted per app. Runs the session-refresh proxy on
|
|
21
|
+
* everything except Next internals and genuine static assets.
|
|
22
|
+
*
|
|
23
|
+
* The image-extension carve-out is scoped with a negative lookahead for an "api/" path segment, so
|
|
24
|
+
* it can only ever match real static files (e.g. "/favicon.svg", "/og.png") — NEVER a route whose
|
|
25
|
+
* dynamic "[id]" segment happens to end in an image extension. Without that guard,
|
|
26
|
+
* "PATCH /api/thing/{id}.png" escaped the gate entirely: the extension satisfied the exclusion, yet
|
|
27
|
+
* Next still resolved the handler and ran it unauthenticated. API routes now always hit the proxy.
|
|
28
|
+
* Apps whose routes need in-request gating still call requireUser() / requireApiUser() in the
|
|
29
|
+
* handler — the matcher refreshes the cookie, it does not protect.
|
|
30
|
+
*/
|
|
31
|
+
declare const AUTH_MATCHER = "/((?!_next/static|_next/image|favicon\\.ico|(?!(?:.*/)?api/).*\\.(?:svg|png|jpg|jpeg|gif|webp|ico)$).*)";
|
|
32
|
+
/** Ready-made proxy config: `export const config = authProxyConfig` in an app's `proxy.ts`. */
|
|
33
|
+
declare const authProxyConfig: {
|
|
34
|
+
readonly matcher: readonly ["/((?!_next/static|_next/image|favicon\\.ico|(?!(?:.*/)?api/).*\\.(?:svg|png|jpg|jpeg|gif|webp|ico)$).*)"];
|
|
35
|
+
};
|
|
11
36
|
/**
|
|
12
37
|
* WorkOS (the engine) is "configured" once its three required secrets are present. When it is NOT
|
|
13
38
|
* configured, the seam fails CLOSED (no session → redirect to sign-in) rather than letting requests
|
|
@@ -39,4 +64,4 @@ declare function isAllowedEmail(email: string | null | undefined): boolean;
|
|
|
39
64
|
/** The WorkOS client id, from either the server or the public var. */
|
|
40
65
|
declare function workosClientId(): string;
|
|
41
66
|
|
|
42
|
-
export { DEFAULT_PUBLIC_PATHS, allowedEmailDomains, assertEmailDomainGate, isAllowedEmail, isPublicPath, isWorkosConfigured, publicPaths, requiresEmailDomainGate, workosClientId };
|
|
67
|
+
export { AUTH_MATCHER, DEFAULT_PUBLIC_PATHS, allowedEmailDomains, appPublicPaths, assertEmailDomainGate, authProxyConfig, isAllowedEmail, isPublicPath, isWorkosConfigured, publicPaths, requiresEmailDomainGate, workosClientId };
|
package/dist/config.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { DEFAULT_PUBLIC_PATHS, allowedEmailDomains, assertEmailDomainGate, isAllowedEmail, isPublicPath, isWorkosConfigured, publicPaths, requiresEmailDomainGate, workosClientId } from './chunk-
|
|
1
|
+
export { AUTH_MATCHER, DEFAULT_PUBLIC_PATHS, allowedEmailDomains, appPublicPaths, assertEmailDomainGate, authProxyConfig, isAllowedEmail, isPublicPath, isWorkosConfigured, publicPaths, requiresEmailDomainGate, workosClientId } from './chunk-ELKYJ3OA.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { R as Role } from './domain-CmEhGW2N.js';
|
|
2
2
|
export { I as Invite, M as Member, O as OrgMembership, S as Session, U as User } from './domain-CmEhGW2N.js';
|
|
3
|
-
export { DEFAULT_PUBLIC_PATHS, allowedEmailDomains, isAllowedEmail, isPublicPath, isWorkosConfigured, publicPaths, workosClientId } from './config.js';
|
|
3
|
+
export { AUTH_MATCHER, DEFAULT_PUBLIC_PATHS, allowedEmailDomains, appPublicPaths, authProxyConfig, isAllowedEmail, isPublicPath, isWorkosConfigured, publicPaths, workosClientId } from './config.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* The identity/tenancy port. WorkOS owns organizations, memberships (+ roles) and invitations; this
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { DEFAULT_PUBLIC_PATHS, allowedEmailDomains, isAllowedEmail, isPublicPath, isWorkosConfigured, publicPaths, workosClientId } from './chunk-
|
|
1
|
+
export { AUTH_MATCHER, DEFAULT_PUBLIC_PATHS, allowedEmailDomains, appPublicPaths, authProxyConfig, isAllowedEmail, isPublicPath, isWorkosConfigured, publicPaths, workosClientId } from './chunk-ELKYJ3OA.js';
|
|
2
2
|
|
|
3
3
|
// src/identity/workos-gateway.ts
|
|
4
4
|
var ROLES = ["owner", "admin", "member"];
|
package/dist/nextjs/index.d.ts
CHANGED
|
@@ -1,10 +1,27 @@
|
|
|
1
|
-
import { U as User, S as Session } from '../domain-CmEhGW2N.js';
|
|
2
1
|
import * as next_server from 'next/server';
|
|
2
|
+
import { NextResponse, NextMiddleware, NextRequest, NextFetchEvent } from 'next/server';
|
|
3
|
+
import { U as User, S as Session } from '../domain-CmEhGW2N.js';
|
|
4
|
+
export { AUTH_MATCHER, authProxyConfig } from '../config.js';
|
|
3
5
|
|
|
4
6
|
/** The signed-in Spawn user, or null. Applies the optional email-domain gate. */
|
|
5
7
|
declare function currentUser(): Promise<User | null>;
|
|
6
8
|
/** The signed-in user; redirects to `/login` when absent. */
|
|
7
9
|
declare function requireUser(redirectTo?: string): Promise<User>;
|
|
10
|
+
/**
|
|
11
|
+
* The API-route counterpart to `requireUser()`. Returns the signed-in `User`, or a `401` JSON
|
|
12
|
+
* `NextResponse` when there is no valid session.
|
|
13
|
+
*
|
|
14
|
+
* Why not just `requireUser()` in an API handler: `requireUser()` redirects to `/login`, which is
|
|
15
|
+
* right for a browser navigation but wrong for a `fetch()` — the caller gets a `200` HTML login
|
|
16
|
+
* page and a JSON parse error instead of a clean `401`. Route handlers should branch on the type:
|
|
17
|
+
*
|
|
18
|
+
* const user = await requireApiUser();
|
|
19
|
+
* if (user instanceof NextResponse) return user; // 401
|
|
20
|
+
* // ...use `user`
|
|
21
|
+
*
|
|
22
|
+
* Applies the same email-domain gate + dynamic-render marking as `currentUser()`.
|
|
23
|
+
*/
|
|
24
|
+
declare function requireApiUser(): Promise<User | NextResponse>;
|
|
8
25
|
/** The full Spawn session (user + active org + role), or null. */
|
|
9
26
|
declare function session(): Promise<Session | null>;
|
|
10
27
|
/** The signed-in email BEFORE the domain gate, if any — lets a login page show a wrong-domain denial. */
|
|
@@ -20,10 +37,16 @@ declare function userDisplayName(user: User): string;
|
|
|
20
37
|
* The app middleware/proxy. Because Spawn renders its OWN auth screens (headless), this only
|
|
21
38
|
* **refreshes** the WorkOS session cookie on each request — it does NOT redirect to any hosted page.
|
|
22
39
|
* Route protection is done in-app: authed layouts call `requireUser()`, which redirects
|
|
23
|
-
* unauthenticated visitors to `/login` (a Spawn screen). Use as the app's `proxy.ts` default export
|
|
40
|
+
* unauthenticated visitors to `/login` (a Spawn screen). Use as the app's `proxy.ts` default export,
|
|
41
|
+
* with the shared hardened matcher (`authProxyConfig`) — do NOT hand-write the regex:
|
|
24
42
|
*
|
|
43
|
+
* import { authProxy } from "@spawn-llc/auth/nextjs";
|
|
44
|
+
* import { authProxyConfig } from "@spawn-llc/auth/config";
|
|
25
45
|
* export default authProxy();
|
|
26
|
-
* export const config =
|
|
46
|
+
* export const config = authProxyConfig;
|
|
47
|
+
*
|
|
48
|
+
* When an app needs its own fail-closed behavior for the WORKOS-unconfigured case (a preview deploy
|
|
49
|
+
* with no secrets), wrap with `safeAuthProxy` from a `middleware.ts` instead of `proxy.ts`.
|
|
27
50
|
*
|
|
28
51
|
* Pass `{ enforce: true }` only if you want middleware-level gating to WorkOS's hosted UI instead
|
|
29
52
|
* of your own screens (not the Spawn default).
|
|
@@ -43,7 +66,37 @@ declare function userDisplayName(user: User): string;
|
|
|
43
66
|
declare function authProxy(options?: {
|
|
44
67
|
enforce?: boolean;
|
|
45
68
|
unauthenticatedPaths?: string[];
|
|
46
|
-
}):
|
|
69
|
+
}): NextMiddleware;
|
|
70
|
+
/**
|
|
71
|
+
* `authProxy()`, but fail CLOSED when WorkOS is not configured.
|
|
72
|
+
*
|
|
73
|
+
* `authProxy()` assumes the WORKOS_* secrets are present; a build/preview deploy without them would
|
|
74
|
+
* otherwise refresh nothing and let every request through. Rather than each app hand-rolling that
|
|
75
|
+
* guard three different ways (redirect / 404 / boot-assert), `safeAuthProxy` owns the plumbing:
|
|
76
|
+
* when identity is configured it delegates to `authProxy(options)`; when it is NOT, it calls the
|
|
77
|
+
* app-supplied `onUnconfigured` handler so the app keeps its own fallback (redirect to `/login`,
|
|
78
|
+
* 404 the gated area, `NextResponse.next()` for a public-only preview, …).
|
|
79
|
+
*
|
|
80
|
+
* // middleware.ts (this wraps the proxy, so it is a middleware, not a bare proxy)
|
|
81
|
+
* import { safeAuthProxy } from "@spawn-llc/auth/nextjs";
|
|
82
|
+
* import { authProxyConfig, isPublicPath } from "@spawn-llc/auth/config";
|
|
83
|
+
* import { NextResponse } from "next/server";
|
|
84
|
+
* export default safeAuthProxy({
|
|
85
|
+
* onUnconfigured: (req) =>
|
|
86
|
+
* isPublicPath(req.nextUrl.pathname)
|
|
87
|
+
* ? NextResponse.next()
|
|
88
|
+
* : NextResponse.redirect(new URL("/login", req.url)),
|
|
89
|
+
* });
|
|
90
|
+
* export const config = authProxyConfig;
|
|
91
|
+
*
|
|
92
|
+
* The configured/unconfigured decision is made ONCE, when the middleware is constructed (module
|
|
93
|
+
* load) — identity config does not change between requests within a running process.
|
|
94
|
+
*/
|
|
95
|
+
declare function safeAuthProxy(options: {
|
|
96
|
+
onUnconfigured: (request: NextRequest, event: NextFetchEvent) => ReturnType<NextMiddleware>;
|
|
97
|
+
enforce?: boolean;
|
|
98
|
+
unauthenticatedPaths?: string[];
|
|
99
|
+
}): NextMiddleware;
|
|
47
100
|
|
|
48
101
|
/**
|
|
49
102
|
* The OAuth callback handler for the app's `/callback` route:
|
|
@@ -133,4 +186,4 @@ declare function startOAuth(input: {
|
|
|
133
186
|
redirectUri?: string;
|
|
134
187
|
}): Promise<string>;
|
|
135
188
|
|
|
136
|
-
export { type FlowResult, type OAuthProvider, authProxy, currentUser, handleCallback, rejectedEmail, requestPasswordReset, requireUser, resetPassword, session, signInWithPassword, signOut, signUp, startOAuth, switchOrganization, userDisplayName, verifyEmail };
|
|
189
|
+
export { type FlowResult, type OAuthProvider, authProxy, currentUser, handleCallback, rejectedEmail, requestPasswordReset, requireApiUser, requireUser, resetPassword, safeAuthProxy, session, signInWithPassword, signOut, signUp, startOAuth, switchOrganization, userDisplayName, verifyEmail };
|
package/dist/nextjs/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { isWorkosConfigured, isAllowedEmail, publicPaths, workosClientId } from '../chunk-
|
|
1
|
+
import { isWorkosConfigured, isAllowedEmail, publicPaths, workosClientId } from '../chunk-ELKYJ3OA.js';
|
|
2
|
+
export { AUTH_MATCHER, authProxyConfig } from '../chunk-ELKYJ3OA.js';
|
|
2
3
|
import { headers, cookies } from 'next/headers';
|
|
3
4
|
import { redirect } from 'next/navigation';
|
|
5
|
+
import { NextResponse } from 'next/server';
|
|
4
6
|
import { authkitMiddleware, handleAuth, getWorkOS, saveSession } from '@workos-inc/authkit-nextjs';
|
|
5
7
|
|
|
6
8
|
async function markDynamic() {
|
|
@@ -19,6 +21,11 @@ async function requireUser(redirectTo = "/login") {
|
|
|
19
21
|
if (!user) redirect(redirectTo);
|
|
20
22
|
return user;
|
|
21
23
|
}
|
|
24
|
+
async function requireApiUser() {
|
|
25
|
+
const user = await currentUser();
|
|
26
|
+
if (user) return user;
|
|
27
|
+
return NextResponse.json({ error: "Not authenticated" }, { status: 401 });
|
|
28
|
+
}
|
|
22
29
|
async function session() {
|
|
23
30
|
await markDynamic();
|
|
24
31
|
if (!isWorkosConfigured()) return null;
|
|
@@ -68,6 +75,10 @@ function authProxy(options) {
|
|
|
68
75
|
}
|
|
69
76
|
return authkitMiddleware();
|
|
70
77
|
}
|
|
78
|
+
function safeAuthProxy(options) {
|
|
79
|
+
const proxy = isWorkosConfigured() ? authProxy({ enforce: options.enforce, unauthenticatedPaths: options.unauthenticatedPaths }) : null;
|
|
80
|
+
return (request, event) => proxy ? proxy(request, event) : options.onUnconfigured(request, event);
|
|
81
|
+
}
|
|
71
82
|
function handleCallback(options) {
|
|
72
83
|
return handleAuth({ returnPathname: options?.returnPathname ?? "/" });
|
|
73
84
|
}
|
|
@@ -266,4 +277,4 @@ async function startOAuth(input) {
|
|
|
266
277
|
});
|
|
267
278
|
}
|
|
268
279
|
|
|
269
|
-
export { authProxy, currentUser, handleCallback, rejectedEmail, requestPasswordReset, requireUser, resetPassword, session, signInWithPassword, signOut, signUp, startOAuth, switchOrganization, userDisplayName, verifyEmail };
|
|
280
|
+
export { authProxy, currentUser, handleCallback, rejectedEmail, requestPasswordReset, requireApiUser, requireUser, resetPassword, safeAuthProxy, session, signInWithPassword, signOut, signUp, startOAuth, switchOrganization, userDisplayName, verifyEmail };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spawn-llc/auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Spawn shared identity — headless auth for the whole Spawn suite. One WorkOS project (named \"Spawn\") backs every app; this is the only place that touches it. WorkOS is an invisible engine.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|