@nwire/auth 0.7.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/LICENSE +21 -0
- package/README.md +77 -0
- package/dist/__tests__/auth.test.d.ts +6 -0
- package/dist/__tests__/auth.test.d.ts.map +1 -0
- package/dist/__tests__/auth.test.js +91 -0
- package/dist/__tests__/auth.test.js.map +1 -0
- package/dist/__tests__/identity.test.d.ts +12 -0
- package/dist/__tests__/identity.test.d.ts.map +1 -0
- package/dist/__tests__/identity.test.js +141 -0
- package/dist/__tests__/identity.test.js.map +1 -0
- package/dist/__tests__/routes.test.d.ts +12 -0
- package/dist/__tests__/routes.test.d.ts.map +1 -0
- package/dist/__tests__/routes.test.js +99 -0
- package/dist/__tests__/routes.test.js.map +1 -0
- package/dist/auth.d.ts +46 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +51 -0
- package/dist/auth.js.map +1 -0
- package/dist/identity.d.ts +85 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +35 -0
- package/dist/identity.js.map +1 -0
- package/dist/resolvers.d.ts +65 -0
- package/dist/resolvers.d.ts.map +1 -0
- package/dist/resolvers.js +181 -0
- package/dist/resolvers.js.map +1 -0
- package/dist/routes.d.ts +99 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/routes.js +252 -0
- package/dist/routes.js.map +1 -0
- package/dist/user.d.ts +44 -0
- package/dist/user.d.ts.map +1 -0
- package/dist/user.js +2 -0
- package/dist/user.js.map +1 -0
- package/package.json +45 -0
package/dist/routes.js
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth routes — `{name}Route` + `{name}Handler` pairs for every canonical
|
|
3
|
+
* identity operation. Mount them on any `httpInterface` directly or via
|
|
4
|
+
* the `mountAuth(api)` helper:
|
|
5
|
+
*
|
|
6
|
+
* import { httpInterface } from "@nwire/http";
|
|
7
|
+
* import { mountAuth, identityPlugin } from "@nwire/auth";
|
|
8
|
+
*
|
|
9
|
+
* const api = mountAuth(httpInterface({ prefix: "/api/v1" }));
|
|
10
|
+
* // mounts: POST /auth/sign-in, /sign-out, /refresh, /register,
|
|
11
|
+
* // /request-password-reset, /reset-password, /verify-email,
|
|
12
|
+
* // GET /auth/me
|
|
13
|
+
*
|
|
14
|
+
* const app = createApp({
|
|
15
|
+
* plugins: [identityPlugin({ adapter })],
|
|
16
|
+
* ...
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* // app.runtime registers "idp" on the container; handlers resolve it
|
|
20
|
+
* await endpoint("api").serve(app).serve(api).run();
|
|
21
|
+
*
|
|
22
|
+
* Each handler reads `idp` from the container (registered by
|
|
23
|
+
* `identityPlugin`) and delegates the business logic to the adapter.
|
|
24
|
+
* Apps that want only a subset of operations import individual
|
|
25
|
+
* `{Route, Handler}` pairs and wire them by hand instead of using
|
|
26
|
+
* `mountAuth`.
|
|
27
|
+
*/
|
|
28
|
+
import { z } from "zod";
|
|
29
|
+
import { defineResource, NotFound } from "@nwire/forge";
|
|
30
|
+
import { post, get } from "@nwire/http";
|
|
31
|
+
import { response } from "@nwire/handler";
|
|
32
|
+
// ─── Resources (response shapes) ───────────────────────────────────
|
|
33
|
+
const UserResource = defineResource("User", {
|
|
34
|
+
schema: z.object({
|
|
35
|
+
id: z.string(),
|
|
36
|
+
email: z.string().optional(),
|
|
37
|
+
name: z.string().optional(),
|
|
38
|
+
roles: z.array(z.string()).readonly().optional(),
|
|
39
|
+
tenant: z.string().optional(),
|
|
40
|
+
}),
|
|
41
|
+
});
|
|
42
|
+
const TokensResource = defineResource("AuthTokens", {
|
|
43
|
+
schema: z.object({
|
|
44
|
+
accessToken: z.string(),
|
|
45
|
+
refreshToken: z.string().optional(),
|
|
46
|
+
idToken: z.string().optional(),
|
|
47
|
+
expiresAt: z.number().optional(),
|
|
48
|
+
tokenType: z.enum(["Bearer", "Cookie"]).optional(),
|
|
49
|
+
}),
|
|
50
|
+
});
|
|
51
|
+
const SignInResource = defineResource("SignInResult", {
|
|
52
|
+
schema: z.object({
|
|
53
|
+
user: UserResource.schema,
|
|
54
|
+
tokens: TokensResource.schema,
|
|
55
|
+
}),
|
|
56
|
+
});
|
|
57
|
+
const ok202 = response(202);
|
|
58
|
+
const ok200User = response(200, UserResource);
|
|
59
|
+
const ok200SignIn = response(200, SignInResource);
|
|
60
|
+
const ok200Tokens = response(200, TokensResource);
|
|
61
|
+
// ─── Schemas ───────────────────────────────────────────────────────
|
|
62
|
+
const SignInBody = z.object({ email: z.email(), password: z.string().min(1) });
|
|
63
|
+
const SignOutBody = z.object({ token: z.string() });
|
|
64
|
+
const RefreshBody = z.object({ refreshToken: z.string() });
|
|
65
|
+
const RegisterBody = z.object({
|
|
66
|
+
email: z.email(),
|
|
67
|
+
password: z.string().min(8),
|
|
68
|
+
name: z.string().optional(),
|
|
69
|
+
});
|
|
70
|
+
const RequestPwResetBody = z.object({ email: z.email() });
|
|
71
|
+
const ResetPasswordBody = z.object({ resetToken: z.string(), newPassword: z.string().min(8) });
|
|
72
|
+
const VerifyEmailBody = z.object({ verificationToken: z.string() });
|
|
73
|
+
const MeBody = z.object({ token: z.string() });
|
|
74
|
+
// ─── Routes + Handlers ─────────────────────────────────────────────
|
|
75
|
+
export const signInRoute = post("/auth/sign-in", {
|
|
76
|
+
body: SignInBody,
|
|
77
|
+
openapi: {
|
|
78
|
+
operation: "auth.SignIn",
|
|
79
|
+
version: 1,
|
|
80
|
+
status: "active",
|
|
81
|
+
summary: "Authenticate with email + password",
|
|
82
|
+
tags: ["Auth"],
|
|
83
|
+
returns: [ok200SignIn],
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
export const signInHandler = async ({ input, resolve }) => {
|
|
87
|
+
const idp = resolve("idp");
|
|
88
|
+
const result = await idp.signIn({ email: input.email, password: input.password });
|
|
89
|
+
return ok200SignIn(result);
|
|
90
|
+
};
|
|
91
|
+
export const signOutRoute = post("/auth/sign-out", {
|
|
92
|
+
body: SignOutBody,
|
|
93
|
+
openapi: {
|
|
94
|
+
operation: "auth.SignOut",
|
|
95
|
+
version: 1,
|
|
96
|
+
status: "active",
|
|
97
|
+
summary: "Invalidate the current session/token",
|
|
98
|
+
tags: ["Auth"],
|
|
99
|
+
returns: [ok202],
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
export const signOutHandler = async ({ input, resolve }) => {
|
|
103
|
+
const idp = resolve("idp");
|
|
104
|
+
await idp.signOut(input.token);
|
|
105
|
+
return ok202();
|
|
106
|
+
};
|
|
107
|
+
export const refreshRoute = post("/auth/refresh", {
|
|
108
|
+
body: RefreshBody,
|
|
109
|
+
openapi: {
|
|
110
|
+
operation: "auth.Refresh",
|
|
111
|
+
version: 1,
|
|
112
|
+
status: "active",
|
|
113
|
+
summary: "Exchange a refresh token for a new access token",
|
|
114
|
+
tags: ["Auth"],
|
|
115
|
+
returns: [ok200Tokens],
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
export const refreshHandler = async ({ input, resolve }) => {
|
|
119
|
+
const idp = resolve("idp");
|
|
120
|
+
if (!idp.refresh)
|
|
121
|
+
throw NotFound.with({ operation: "auth.Refresh", reason: "not supported by adapter" });
|
|
122
|
+
const tokens = await idp.refresh(input.refreshToken);
|
|
123
|
+
return ok200Tokens(tokens);
|
|
124
|
+
};
|
|
125
|
+
export const registerRoute = post("/auth/register", {
|
|
126
|
+
body: RegisterBody,
|
|
127
|
+
openapi: {
|
|
128
|
+
operation: "auth.Register",
|
|
129
|
+
version: 1,
|
|
130
|
+
status: "active",
|
|
131
|
+
summary: "Create a new account",
|
|
132
|
+
tags: ["Auth"],
|
|
133
|
+
returns: [ok200SignIn],
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
export const registerHandler = async ({ input, resolve }) => {
|
|
137
|
+
const idp = resolve("idp");
|
|
138
|
+
if (!idp.register)
|
|
139
|
+
throw NotFound.with({ operation: "auth.Register", reason: "not supported by adapter" });
|
|
140
|
+
const result = await idp.register({
|
|
141
|
+
email: input.email,
|
|
142
|
+
password: input.password,
|
|
143
|
+
name: input.name,
|
|
144
|
+
});
|
|
145
|
+
return ok200SignIn({
|
|
146
|
+
user: result.user,
|
|
147
|
+
tokens: result.tokens ?? { accessToken: "" },
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
export const requestPasswordResetRoute = post("/auth/request-password-reset", {
|
|
151
|
+
body: RequestPwResetBody,
|
|
152
|
+
openapi: {
|
|
153
|
+
operation: "auth.RequestPasswordReset",
|
|
154
|
+
version: 1,
|
|
155
|
+
status: "active",
|
|
156
|
+
summary: "Send a password-reset email",
|
|
157
|
+
tags: ["Auth"],
|
|
158
|
+
returns: [ok202],
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
export const requestPasswordResetHandler = async ({ input, resolve, }) => {
|
|
162
|
+
const idp = resolve("idp");
|
|
163
|
+
if (!idp.requestPasswordReset)
|
|
164
|
+
throw NotFound.with({ operation: "auth.RequestPasswordReset" });
|
|
165
|
+
await idp.requestPasswordReset(input.email);
|
|
166
|
+
return ok202();
|
|
167
|
+
};
|
|
168
|
+
export const resetPasswordRoute = post("/auth/reset-password", {
|
|
169
|
+
body: ResetPasswordBody,
|
|
170
|
+
openapi: {
|
|
171
|
+
operation: "auth.ResetPassword",
|
|
172
|
+
version: 1,
|
|
173
|
+
status: "active",
|
|
174
|
+
summary: "Consume a reset token + set a new password",
|
|
175
|
+
tags: ["Auth"],
|
|
176
|
+
returns: [ok202],
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
export const resetPasswordHandler = async ({ input, resolve }) => {
|
|
180
|
+
const idp = resolve("idp");
|
|
181
|
+
if (!idp.resetPassword)
|
|
182
|
+
throw NotFound.with({ operation: "auth.ResetPassword" });
|
|
183
|
+
await idp.resetPassword(input.resetToken, input.newPassword);
|
|
184
|
+
return ok202();
|
|
185
|
+
};
|
|
186
|
+
export const verifyEmailRoute = post("/auth/verify-email", {
|
|
187
|
+
body: VerifyEmailBody,
|
|
188
|
+
openapi: {
|
|
189
|
+
operation: "auth.VerifyEmail",
|
|
190
|
+
version: 1,
|
|
191
|
+
status: "active",
|
|
192
|
+
summary: "Confirm an email-verification token",
|
|
193
|
+
tags: ["Auth"],
|
|
194
|
+
returns: [ok202],
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
export const verifyEmailHandler = async ({ input, resolve }) => {
|
|
198
|
+
const idp = resolve("idp");
|
|
199
|
+
if (!idp.verifyEmail)
|
|
200
|
+
throw NotFound.with({ operation: "auth.VerifyEmail" });
|
|
201
|
+
await idp.verifyEmail(input.verificationToken);
|
|
202
|
+
return ok202();
|
|
203
|
+
};
|
|
204
|
+
export const meRoute = get("/auth/me", {
|
|
205
|
+
body: MeBody,
|
|
206
|
+
openapi: {
|
|
207
|
+
operation: "auth.Me",
|
|
208
|
+
version: 1,
|
|
209
|
+
status: "active",
|
|
210
|
+
summary: "Return the User identified by the current Authorization token",
|
|
211
|
+
tags: ["Auth"],
|
|
212
|
+
returns: [ok200User],
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
export const meHandler = async ({ input, resolve }) => {
|
|
216
|
+
const idp = resolve("idp");
|
|
217
|
+
const user = await idp.verifyToken(input.token);
|
|
218
|
+
if (!user)
|
|
219
|
+
throw NotFound.with({ operation: "auth.Me", reason: "token does not resolve to a user" });
|
|
220
|
+
return ok200User(user);
|
|
221
|
+
};
|
|
222
|
+
/**
|
|
223
|
+
* Wire every canonical auth route onto the given httpInterface in one
|
|
224
|
+
* call. Returns the same interface for chaining. Pass `options.include`
|
|
225
|
+
* to mount only a subset (e.g. an app that doesn't expose registration).
|
|
226
|
+
*
|
|
227
|
+
* const api = mountAuth(httpInterface({ prefix: "/api/v1" }));
|
|
228
|
+
* // → 8 routes mounted: /auth/sign-in, /sign-out, /refresh, /register, ...
|
|
229
|
+
*
|
|
230
|
+
* // Subset:
|
|
231
|
+
* mountAuth(api, { include: ["signIn", "signOut", "me"] });
|
|
232
|
+
*/
|
|
233
|
+
export function mountAuth(api, options) {
|
|
234
|
+
const all = {
|
|
235
|
+
signIn: [signInRoute, signInHandler],
|
|
236
|
+
signOut: [signOutRoute, signOutHandler],
|
|
237
|
+
refresh: [refreshRoute, refreshHandler],
|
|
238
|
+
register: [registerRoute, registerHandler],
|
|
239
|
+
requestPasswordReset: [requestPasswordResetRoute, requestPasswordResetHandler],
|
|
240
|
+
resetPassword: [resetPasswordRoute, resetPasswordHandler],
|
|
241
|
+
verifyEmail: [verifyEmailRoute, verifyEmailHandler],
|
|
242
|
+
me: [meRoute, meHandler],
|
|
243
|
+
};
|
|
244
|
+
const keys = options?.include ?? Object.keys(all);
|
|
245
|
+
for (const k of keys) {
|
|
246
|
+
const [route, handler] = all[k];
|
|
247
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
248
|
+
api.wire(route, handler);
|
|
249
|
+
}
|
|
250
|
+
return api;
|
|
251
|
+
}
|
|
252
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"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"}
|
package/dist/user.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `User` — the canonical identity shape every adapter produces and every
|
|
3
|
+
* handler sees on `ctx.user`. Adapters (Logto, better-auth, Passport, …)
|
|
4
|
+
* translate their provider-specific user shapes into this interface.
|
|
5
|
+
*
|
|
6
|
+
* Extensibility via declaration merging — the same trick Express / Hono /
|
|
7
|
+
* Fastify use. Apps add their fields once, globally, and every
|
|
8
|
+
* `ctx.user.fieldName` access is typed.
|
|
9
|
+
*
|
|
10
|
+
* // somewhere in your app, once:
|
|
11
|
+
* declare module "@nwire/auth" {
|
|
12
|
+
* interface User {
|
|
13
|
+
* readonly accountId: string;
|
|
14
|
+
* readonly plan: "free" | "pro" | "enterprise";
|
|
15
|
+
* }
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* Adapter authors: provide the base fields; let users add domain-specific
|
|
19
|
+
* fields through merging.
|
|
20
|
+
*/
|
|
21
|
+
export interface User {
|
|
22
|
+
/** Stable identifier — what envelope.userId carries. */
|
|
23
|
+
readonly id: string;
|
|
24
|
+
/** Display email if the IdP knows it. */
|
|
25
|
+
readonly email?: string;
|
|
26
|
+
/** Human-readable name. */
|
|
27
|
+
readonly name?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Authorization roles — coarse-grained groupings ("admin", "editor").
|
|
30
|
+
* Adapters fill this in from their native role mechanism. Feeds RBAC.
|
|
31
|
+
*/
|
|
32
|
+
readonly roles?: readonly string[];
|
|
33
|
+
/**
|
|
34
|
+
* OAuth/OIDC scopes — fine-grained capabilities ("read:posts",
|
|
35
|
+
* "write:billing", "manage:users"). Logto-style IdPs expose these as
|
|
36
|
+
* the standard `scope` claim; adapters split it into an array. Use
|
|
37
|
+
* scopes when a permission is verb-on-resource specific; roles for
|
|
38
|
+
* org-level groupings.
|
|
39
|
+
*/
|
|
40
|
+
readonly scopes?: readonly string[];
|
|
41
|
+
/** Tenant the user belongs to — propagates to envelope.tenant. */
|
|
42
|
+
readonly tenant?: string;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=user.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../src/user.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,IAAI;IACnB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,2BAA2B;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,kEAAkE;IAClE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B"}
|
package/dist/user.js
ADDED
package/dist/user.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user.js","sourceRoot":"","sources":["../src/user.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nwire/auth",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "Nwire — authorization contract + middleware. Authorizer interface (throw-on-deny) + authzMiddleware. Per-action `policy` tag is opaque to the framework; the authorizer decides what each tag means.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"auth",
|
|
7
|
+
"authz",
|
|
8
|
+
"middleware",
|
|
9
|
+
"nwire",
|
|
10
|
+
"policy"
|
|
11
|
+
],
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./dist/auth.js",
|
|
18
|
+
"types": "./dist/auth.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"import": "./dist/auth.js",
|
|
22
|
+
"types": "./dist/auth.d.ts"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"zod": "^4.0.0",
|
|
30
|
+
"@nwire/forge": "0.7.0",
|
|
31
|
+
"@nwire/http": "0.7.0",
|
|
32
|
+
"@nwire/handler": "0.7.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^22.19.9",
|
|
36
|
+
"typescript": "^5.9.3",
|
|
37
|
+
"vitest": "^4.0.18",
|
|
38
|
+
"@nwire/envelope": "0.7.0"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsc && node ../../scripts/fix-dist-extensions.mjs dist",
|
|
42
|
+
"dev": "tsc --watch",
|
|
43
|
+
"typecheck": "tsc --noEmit"
|
|
44
|
+
}
|
|
45
|
+
}
|