@authu/node 0.1.18

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,214 @@
1
+ # @authu/node
2
+
3
+ Node.js SDK for AuthU - Centralized Multi-Tenant Authentication Service.
4
+
5
+ ## Installation
6
+
7
+ ```sh
8
+ npm install @authu/node
9
+ # or
10
+ pnpm add @authu/node
11
+ # or
12
+ yarn add @authu/node
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ### 1. Verify JWT Tokens
18
+
19
+ Use `verifyToken` to validate and decode JWT tokens:
20
+
21
+ ```typescript
22
+ import {verifyToken} from '@authu/node';
23
+
24
+ const result = await verifyToken(token, {
25
+ domain: 'auth.example.com',
26
+ audience: 'https://api.example.com'
27
+ });
28
+
29
+ console.log(result.payload.sub); // User ID
30
+ console.log(result.payload.email); // User email
31
+ ```
32
+
33
+ ### 2. Fastify Middleware
34
+
35
+ Use `createAuthUMiddleware` to protect your Fastify routes:
36
+
37
+ ```typescript
38
+ import Fastify from 'fastify';
39
+ import {createAuthUMiddleware} from '@authu/node';
40
+
41
+ const fastify = Fastify();
42
+
43
+ // Register the middleware
44
+ fastify.register(
45
+ createAuthUMiddleware({
46
+ domain: 'auth.example.com',
47
+ audience: 'https://api.example.com'
48
+ })
49
+ );
50
+
51
+ // Protected route
52
+ fastify.get(
53
+ '/api/profile',
54
+ {preHandler: [fastify.verifyAuthU]},
55
+ async request => {
56
+ // Access the authenticated user
57
+ return {user: request.authUUser};
58
+ }
59
+ );
60
+ ```
61
+
62
+ ### 3. Optional Authentication
63
+
64
+ For routes where authentication is optional:
65
+
66
+ ```typescript
67
+ fastify.register(
68
+ createAuthUMiddleware({
69
+ domain: 'auth.example.com',
70
+ optional: true
71
+ })
72
+ );
73
+
74
+ fastify.get('/api/public', {preHandler: [fastify.verifyAuthU]}, async request => {
75
+ if (request.authUUser) {
76
+ return {message: `Hello ${request.authUUser.name}`};
77
+ }
78
+ return {message: 'Hello guest'};
79
+ });
80
+ ```
81
+
82
+ ### 4. Custom JWKS Client
83
+
84
+ For advanced use cases, you can provide your own JWKS client:
85
+
86
+ ```typescript
87
+ import {JwksClient, verifyToken} from '@authu/node';
88
+
89
+ const jwksClient = new JwksClient({
90
+ jwksUri: 'https://auth.example.com/.well-known/jwks.json',
91
+ cacheMaxAge: 300000 // 5 minutes cache
92
+ });
93
+
94
+ const result = await verifyToken(token, {
95
+ domain: 'auth.example.com',
96
+ jwksClient
97
+ });
98
+ ```
99
+
100
+ ## API Reference
101
+
102
+ ### verifyToken(token, options)
103
+
104
+ Verifies and decodes a JWT token.
105
+
106
+ **Options:**
107
+
108
+ | Option | Type | Required | Description |
109
+ |--------|------|----------|-------------|
110
+ | `domain` | `string` | Yes | AuthU server domain (without https://) |
111
+ | `audience` | `string` | No | Expected audience claim |
112
+ | `issuer` | `string` | No | Expected issuer (default: `https://{domain}`) |
113
+ | `jwksClient` | `JwksClient` | No | Custom JWKS client instance |
114
+
115
+ **Returns:** `Promise<VerifiedToken>`
116
+
117
+ ### createAuthUMiddleware(options)
118
+
119
+ Creates a Fastify plugin for JWT authentication.
120
+
121
+ **Options:**
122
+
123
+ | Option | Type | Required | Description |
124
+ |--------|------|----------|-------------|
125
+ | `domain` | `string` | Yes | AuthU server domain |
126
+ | `audience` | `string` | No | Expected audience claim |
127
+ | `issuer` | `string` | No | Expected issuer |
128
+ | `optional` | `boolean` | No | If true, don't error on missing/invalid tokens |
129
+
130
+ **Decorators added:**
131
+
132
+ - `fastify.verifyAuthU` - Prehandler function for route protection
133
+ - `request.authUUser` - Authenticated user data (or null if optional)
134
+
135
+ ### JwksClient
136
+
137
+ JWKS client with automatic caching.
138
+
139
+ ```typescript
140
+ const client = new JwksClient({
141
+ jwksUri: 'https://auth.example.com/.well-known/jwks.json',
142
+ cacheMaxAge: 600000 // 10 minutes (default)
143
+ });
144
+
145
+ // Get a key by kid
146
+ const key = await client.getKey('key-id');
147
+
148
+ // Get all keys
149
+ const jwks = await client.getJwks();
150
+
151
+ // Clear cache
152
+ client.clearCache();
153
+ ```
154
+
155
+ ### Types
156
+
157
+ ```typescript
158
+ interface AuthUUser {
159
+ sub: string;
160
+ email?: string;
161
+ emailVerified?: boolean;
162
+ name?: string;
163
+ picture?: string;
164
+ scope?: string;
165
+ clientId?: string;
166
+ tenantId?: string;
167
+ }
168
+
169
+ interface VerifiedToken {
170
+ payload: AuthUUser;
171
+ header: {
172
+ alg: string;
173
+ typ?: string;
174
+ kid?: string;
175
+ };
176
+ }
177
+ ```
178
+
179
+ ## Development
180
+
181
+ ### Build
182
+
183
+ ```sh
184
+ pnpm run build
185
+ ```
186
+
187
+ ### Lint
188
+
189
+ ```sh
190
+ pnpm run lint
191
+ ```
192
+
193
+ ## Publishing
194
+
195
+ ### Prerequisites
196
+
197
+ - Be logged in to npm: `npm login`
198
+ - Have publish rights on `@authu` scope
199
+
200
+ ### Publish a New Version
201
+
202
+ 1. Update version in `package.json`
203
+ 2. Build and publish:
204
+
205
+ ```sh
206
+ pnpm run build
207
+ pnpm publish --access public
208
+ ```
209
+
210
+ The `--access public` flag is required for scoped packages.
211
+
212
+ ## License
213
+
214
+ MIT
@@ -0,0 +1,5 @@
1
+ export { verifyToken, type VerifyTokenOptions } from './verifyToken.js';
2
+ export { createAuthUMiddleware, type AuthUMiddlewareOptions } from './middleware.js';
3
+ export { JwksClient } from './jwks.js';
4
+ export type { AuthUUser, VerifiedToken, JWK, JWKS } from './types.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAE,KAAK,kBAAkB,EAAC,MAAM,kBAAkB,CAAC;AACtE,OAAO,EACL,qBAAqB,EACrB,KAAK,sBAAsB,EAC5B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAC,UAAU,EAAC,MAAM,WAAW,CAAC;AACrC,YAAY,EAAC,SAAS,EAAE,aAAa,EAAE,GAAG,EAAE,IAAI,EAAC,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { verifyToken } from './verifyToken.js';
2
+ export { createAuthUMiddleware } from './middleware.js';
3
+ export { JwksClient } from './jwks.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAA0B,MAAM,kBAAkB,CAAC;AACtE,OAAO,EACL,qBAAqB,EAEtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAC,UAAU,EAAC,MAAM,WAAW,CAAC"}
package/dist/jwks.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ import * as jose from 'jose';
2
+ import type { JWKS } from './types.js';
3
+ interface JwksClientOptions {
4
+ jwksUri: string;
5
+ cacheMaxAge?: number;
6
+ }
7
+ export declare class JwksClient {
8
+ private jwksUri;
9
+ private cacheMaxAge;
10
+ private cachedJwks;
11
+ private cacheExpiry;
12
+ constructor(options: JwksClientOptions);
13
+ getKey(kid: string): Promise<Awaited<ReturnType<typeof jose.importJWK>>>;
14
+ getJwks(): Promise<JWKS>;
15
+ clearCache(): void;
16
+ }
17
+ export {};
18
+ //# sourceMappingURL=jwks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwks.d.ts","sourceRoot":"","sources":["../src/jwks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,YAAY,CAAC;AAErC,UAAU,iBAAiB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,WAAW,CAAa;gBAEpB,OAAO,EAAE,iBAAiB;IAKhC,MAAM,CACV,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAWhD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB9B,UAAU,IAAI,IAAI;CAInB"}
package/dist/jwks.js ADDED
@@ -0,0 +1,37 @@
1
+ import * as jose from 'jose';
2
+ export class JwksClient {
3
+ jwksUri;
4
+ cacheMaxAge;
5
+ cachedJwks = null;
6
+ cacheExpiry = 0;
7
+ constructor(options) {
8
+ this.jwksUri = options.jwksUri;
9
+ this.cacheMaxAge = options.cacheMaxAge ?? 600000; // 10 minutes default
10
+ }
11
+ async getKey(kid) {
12
+ const jwks = await this.getJwks();
13
+ const key = jwks.keys.find(k => k.kid === kid);
14
+ if (!key) {
15
+ throw new Error(`Key with kid "${kid}" not found in JWKS`);
16
+ }
17
+ return jose.importJWK(key);
18
+ }
19
+ async getJwks() {
20
+ const now = Date.now();
21
+ if (this.cachedJwks && now < this.cacheExpiry) {
22
+ return this.cachedJwks;
23
+ }
24
+ const response = await fetch(this.jwksUri);
25
+ if (!response.ok) {
26
+ throw new Error(`Failed to fetch JWKS: ${response.status} ${response.statusText}`);
27
+ }
28
+ this.cachedJwks = (await response.json());
29
+ this.cacheExpiry = now + this.cacheMaxAge;
30
+ return this.cachedJwks;
31
+ }
32
+ clearCache() {
33
+ this.cachedJwks = null;
34
+ this.cacheExpiry = 0;
35
+ }
36
+ }
37
+ //# sourceMappingURL=jwks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwks.js","sourceRoot":"","sources":["../src/jwks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAQ7B,MAAM,OAAO,UAAU;IACb,OAAO,CAAS;IAChB,WAAW,CAAS;IACpB,UAAU,GAAgB,IAAI,CAAC;IAC/B,WAAW,GAAW,CAAC,CAAC;IAEhC,YAAY,OAA0B;QACpC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,MAAM,CAAC,CAAC,qBAAqB;IACzE,CAAC;IAED,KAAK,CAAC,MAAM,CACV,GAAW;QAEX,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;QAE/C,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,iBAAiB,GAAG,qBAAqB,CAAC,CAAC;QAC7D,CAAC;QAED,OAAO,IAAI,CAAC,SAAS,CAAC,GAAe,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,IAAI,IAAI,CAAC,UAAU,IAAI,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YAC9C,OAAO,IAAI,CAAC,UAAU,CAAC;QACzB,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAE3C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CACb,yBAAyB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAClE,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,UAAU,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAS,CAAC;QAClD,IAAI,CAAC,WAAW,GAAG,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC;QAE1C,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,UAAU;QACR,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;IACvB,CAAC;CACF"}
@@ -0,0 +1,22 @@
1
+ import { type VerifyTokenOptions } from './verifyToken.js';
2
+ import type { AuthUUser } from './types.js';
3
+ export interface AuthUMiddlewareOptions extends VerifyTokenOptions {
4
+ optional?: boolean;
5
+ }
6
+ type FastifyRequest = {
7
+ headers: Record<string, string | string[] | undefined>;
8
+ authUUser?: AuthUUser;
9
+ };
10
+ type FastifyReply = {
11
+ status: (code: number) => FastifyReply;
12
+ send: (body: unknown) => void;
13
+ };
14
+ type FastifyInstance = {
15
+ decorate: (name: string, value: unknown) => void;
16
+ decorateRequest: (name: string, value: unknown) => void;
17
+ addHook: (hookName: string, handler: (request: FastifyRequest, reply: FastifyReply) => Promise<void>) => void;
18
+ };
19
+ type FastifyPluginCallback = (fastify: FastifyInstance, options: AuthUMiddlewareOptions, done: (err?: Error) => void) => void;
20
+ export declare function createAuthUMiddleware(options: AuthUMiddlewareOptions): FastifyPluginCallback;
21
+ export {};
22
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,kBAAkB,EAAC,MAAM,kBAAkB,CAAC;AACtE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAE1C,MAAM,WAAW,sBAAuB,SAAQ,kBAAkB;IAChE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,KAAK,cAAc,GAAG;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB,CAAC;AAEF,KAAK,YAAY,GAAG;IAClB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,YAAY,CAAC;IACvC,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CAC/B,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACxD,OAAO,EAAE,CACP,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,KACrE,IAAI,CAAC;CACX,CAAC;AAEF,KAAK,qBAAqB,GAAG,CAC3B,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,sBAAsB,EAC/B,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,KAAK,IAAI,KACxB,IAAI,CAAC;AAEV,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,sBAAsB,GAC9B,qBAAqB,CA+CvB"}
@@ -0,0 +1,41 @@
1
+ import { verifyToken } from './verifyToken.js';
2
+ export function createAuthUMiddleware(options) {
3
+ return (fastify, _opts, done) => {
4
+ fastify.decorateRequest('authUUser', null);
5
+ fastify.decorate('verifyAuthU', async (request, reply) => {
6
+ const authHeader = request.headers.authorization;
7
+ if (!authHeader || typeof authHeader !== 'string') {
8
+ if (options.optional) {
9
+ return;
10
+ }
11
+ reply.status(401).send({ error: 'Missing authorization header' });
12
+ return;
13
+ }
14
+ const [scheme, token] = authHeader.split(' ');
15
+ if (scheme?.toLowerCase() !== 'bearer' || !token) {
16
+ if (options.optional) {
17
+ return;
18
+ }
19
+ reply
20
+ .status(401)
21
+ .send({ error: 'Invalid authorization header format' });
22
+ return;
23
+ }
24
+ try {
25
+ const verified = await verifyToken(token, options);
26
+ request.authUUser = verified.payload;
27
+ }
28
+ catch (err) {
29
+ if (options.optional) {
30
+ return;
31
+ }
32
+ reply.status(401).send({
33
+ error: 'Invalid token',
34
+ message: err instanceof Error ? err.message : 'Token verification failed'
35
+ });
36
+ }
37
+ });
38
+ done();
39
+ };
40
+ }
41
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAA0B,MAAM,kBAAkB,CAAC;AAgCtE,MAAM,UAAU,qBAAqB,CACnC,OAA+B;IAE/B,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAC9B,OAAO,CAAC,eAAe,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QAE3C,OAAO,CAAC,QAAQ,CACd,aAAa,EACb,KAAK,EAAE,OAAuB,EAAE,KAAmB,EAAiB,EAAE;YACpE,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;YAEjD,IAAI,CAAC,UAAU,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,CAAC;gBAClD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;oBACrB,OAAO;gBACT,CAAC;gBACD,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAC,KAAK,EAAE,8BAA8B,EAAC,CAAC,CAAC;gBAChE,OAAO;YACT,CAAC;YAED,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAE9C,IAAI,MAAM,EAAE,WAAW,EAAE,KAAK,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC;gBACjD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;oBACrB,OAAO;gBACT,CAAC;gBACD,KAAK;qBACF,MAAM,CAAC,GAAG,CAAC;qBACX,IAAI,CAAC,EAAC,KAAK,EAAE,qCAAqC,EAAC,CAAC,CAAC;gBACxD,OAAO;YACT,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;gBACnD,OAAO,CAAC,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC;YACvC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;oBACrB,OAAO;gBACT,CAAC;gBACD,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;oBACrB,KAAK,EAAE,eAAe;oBACtB,OAAO,EACL,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,2BAA2B;iBACnE,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CACF,CAAC;QAEF,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,30 @@
1
+ export interface AuthUUser {
2
+ sub: string;
3
+ email?: string;
4
+ emailVerified?: boolean;
5
+ name?: string;
6
+ picture?: string;
7
+ scope?: string;
8
+ clientId?: string;
9
+ tenantId?: string;
10
+ }
11
+ export interface VerifiedToken {
12
+ payload: AuthUUser;
13
+ header: {
14
+ alg: string;
15
+ typ?: string;
16
+ kid?: string;
17
+ };
18
+ }
19
+ export interface JWK {
20
+ kty: string;
21
+ kid: string;
22
+ use?: string;
23
+ alg?: string;
24
+ n?: string;
25
+ e?: string;
26
+ }
27
+ export interface JWKS {
28
+ keys: JWK[];
29
+ }
30
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,SAAS,CAAC;IACnB,MAAM,EAAE;QACN,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,MAAM,WAAW,GAAG;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,GAAG,EAAE,CAAC;CACb"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,10 @@
1
+ import { JwksClient } from './jwks.js';
2
+ import type { VerifiedToken } from './types.js';
3
+ export interface VerifyTokenOptions {
4
+ domain: string;
5
+ audience?: string;
6
+ issuer?: string;
7
+ jwksClient?: JwksClient;
8
+ }
9
+ export declare function verifyToken(token: string, options: VerifyTokenOptions): Promise<VerifiedToken>;
10
+ //# sourceMappingURL=verifyToken.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifyToken.d.ts","sourceRoot":"","sources":["../src/verifyToken.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,UAAU,EAAC,MAAM,WAAW,CAAC;AACrC,OAAO,KAAK,EAAY,aAAa,EAAC,MAAM,YAAY,CAAC;AAEzD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAgBD,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,aAAa,CAAC,CAuCxB"}
@@ -0,0 +1,44 @@
1
+ import * as jose from 'jose';
2
+ import { JwksClient } from './jwks.js';
3
+ const clientCache = new Map();
4
+ function getJwksClient(domain) {
5
+ if (!clientCache.has(domain)) {
6
+ clientCache.set(domain, new JwksClient({
7
+ jwksUri: `https://${domain}/.well-known/jwks.json`
8
+ }));
9
+ }
10
+ return clientCache.get(domain);
11
+ }
12
+ export async function verifyToken(token, options) {
13
+ const { domain, audience, issuer } = options;
14
+ const jwksClient = options.jwksClient ?? getJwksClient(domain);
15
+ const expectedIssuer = issuer ?? `https://${domain}`;
16
+ const { payload, protectedHeader } = await jose.jwtVerify(token, async (header) => {
17
+ if (!header.kid) {
18
+ throw new Error('Token missing kid header');
19
+ }
20
+ return jwksClient.getKey(header.kid);
21
+ }, {
22
+ issuer: expectedIssuer,
23
+ audience
24
+ });
25
+ const user = {
26
+ sub: payload.sub,
27
+ email: payload.email,
28
+ emailVerified: payload.email_verified,
29
+ name: payload.name,
30
+ picture: payload.picture,
31
+ scope: payload.scope,
32
+ clientId: payload.client_id,
33
+ tenantId: payload.tenant_id
34
+ };
35
+ return {
36
+ payload: user,
37
+ header: {
38
+ alg: protectedHeader.alg,
39
+ typ: protectedHeader.typ,
40
+ kid: protectedHeader.kid
41
+ }
42
+ };
43
+ }
44
+ //# sourceMappingURL=verifyToken.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifyToken.js","sourceRoot":"","sources":["../src/verifyToken.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAC,UAAU,EAAC,MAAM,WAAW,CAAC;AAUrC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAsB,CAAC;AAElD,SAAS,aAAa,CAAC,MAAc;IACnC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,WAAW,CAAC,GAAG,CACb,MAAM,EACN,IAAI,UAAU,CAAC;YACb,OAAO,EAAE,WAAW,MAAM,wBAAwB;SACnD,CAAC,CACH,CAAC;IACJ,CAAC;IACD,OAAO,WAAW,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC;AAClC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAa,EACb,OAA2B;IAE3B,MAAM,EAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAC,GAAG,OAAO,CAAC;IAC3C,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;IAE/D,MAAM,cAAc,GAAG,MAAM,IAAI,WAAW,MAAM,EAAE,CAAC;IAErD,MAAM,EAAC,OAAO,EAAE,eAAe,EAAC,GAAG,MAAM,IAAI,CAAC,SAAS,CACrD,KAAK,EACL,KAAK,EAAC,MAAM,EAAC,EAAE;QACb,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACvC,CAAC,EACD;QACE,MAAM,EAAE,cAAc;QACtB,QAAQ;KACT,CACF,CAAC;IAEF,MAAM,IAAI,GAAc;QACtB,GAAG,EAAE,OAAO,CAAC,GAAa;QAC1B,KAAK,EAAE,OAAO,CAAC,KAA2B;QAC1C,aAAa,EAAE,OAAO,CAAC,cAAqC;QAC5D,IAAI,EAAE,OAAO,CAAC,IAA0B;QACxC,OAAO,EAAE,OAAO,CAAC,OAA6B;QAC9C,KAAK,EAAE,OAAO,CAAC,KAA2B;QAC1C,QAAQ,EAAE,OAAO,CAAC,SAA+B;QACjD,QAAQ,EAAE,OAAO,CAAC,SAA+B;KAClD,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,IAAI;QACb,MAAM,EAAE;YACN,GAAG,EAAE,eAAe,CAAC,GAAG;YACxB,GAAG,EAAE,eAAe,CAAC,GAAG;YACxB,GAAG,EAAE,eAAe,CAAC,GAAG;SACzB;KACF,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@authu/node",
3
+ "version": "0.1.18",
4
+ "description": "Node.js SDK for AuthU - Centralized Multi-Tenant Authentication Service",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "keywords": [
18
+ "authu",
19
+ "auth",
20
+ "authentication",
21
+ "oauth2",
22
+ "oidc",
23
+ "node",
24
+ "fastify",
25
+ "jwt",
26
+ "jwks"
27
+ ],
28
+ "author": "Uralys",
29
+ "license": "MIT",
30
+ "dependencies": {
31
+ "jose": "^6.0.0",
32
+ "@authu/shared": "0.1.18"
33
+ },
34
+ "devDependencies": {
35
+ "@eslint/js": "^9.33.0",
36
+ "@types/node": "^22.10.7",
37
+ "eslint": "^9.33.0",
38
+ "eslint-plugin-prettier": "^5.5.4",
39
+ "prettier": "^3.6.2",
40
+ "typescript": "^5.7.3",
41
+ "typescript-eslint": "^8.40.0"
42
+ },
43
+ "scripts": {
44
+ "build": "tsc",
45
+ "dev": "tsc --watch",
46
+ "eslint": "eslint src --cache",
47
+ "typecheck": "tsc --noEmit",
48
+ "lint": "pnpm run eslint && pnpm run typecheck"
49
+ }
50
+ }