@juspay/neurolink 9.31.2 → 9.32.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 +6 -0
- package/dist/auth/AuthProviderFactory.d.ts +71 -0
- package/dist/auth/AuthProviderFactory.js +111 -0
- package/dist/auth/AuthProviderRegistry.d.ts +33 -0
- package/dist/auth/AuthProviderRegistry.js +190 -0
- package/dist/auth/RequestContext.d.ts +23 -0
- package/dist/auth/RequestContext.js +78 -0
- package/dist/auth/authContext.d.ts +198 -0
- package/dist/auth/authContext.js +314 -0
- package/dist/auth/errors.d.ts +63 -0
- package/dist/auth/errors.js +39 -0
- package/dist/auth/index.d.ts +20 -8
- package/dist/auth/index.js +35 -7
- package/dist/auth/middleware/AuthMiddleware.d.ts +181 -0
- package/dist/auth/middleware/AuthMiddleware.js +519 -0
- package/dist/auth/middleware/rateLimitByUser.d.ts +282 -0
- package/dist/auth/middleware/rateLimitByUser.js +554 -0
- package/dist/auth/providers/BaseAuthProvider.d.ts +259 -0
- package/dist/auth/providers/BaseAuthProvider.js +723 -0
- package/dist/auth/providers/CognitoProvider.d.ts +61 -0
- package/dist/auth/providers/CognitoProvider.js +304 -0
- package/dist/auth/providers/KeycloakProvider.d.ts +61 -0
- package/dist/auth/providers/KeycloakProvider.js +393 -0
- package/dist/auth/providers/auth0.d.ts +59 -0
- package/dist/auth/providers/auth0.js +274 -0
- package/dist/auth/providers/betterAuth.d.ts +51 -0
- package/dist/auth/providers/betterAuth.js +182 -0
- package/dist/auth/providers/clerk.d.ts +65 -0
- package/dist/auth/providers/clerk.js +317 -0
- package/dist/auth/providers/custom.d.ts +64 -0
- package/dist/auth/providers/custom.js +112 -0
- package/dist/auth/providers/firebase.d.ts +63 -0
- package/dist/auth/providers/firebase.js +226 -0
- package/dist/auth/providers/jwt.d.ts +68 -0
- package/dist/auth/providers/jwt.js +212 -0
- package/dist/auth/providers/oauth2.d.ts +73 -0
- package/dist/auth/providers/oauth2.js +303 -0
- package/dist/auth/providers/supabase.d.ts +63 -0
- package/dist/auth/providers/supabase.js +259 -0
- package/dist/auth/providers/workos.d.ts +61 -0
- package/dist/auth/providers/workos.js +284 -0
- package/dist/auth/serverBridge.d.ts +14 -0
- package/dist/auth/serverBridge.js +25 -0
- package/dist/auth/sessionManager.d.ts +142 -0
- package/dist/auth/sessionManager.js +437 -0
- package/dist/cli/commands/authProviders.d.ts +43 -0
- package/dist/cli/commands/authProviders.js +399 -0
- package/dist/cli/factories/authCommandFactory.d.ts +23 -5
- package/dist/cli/factories/authCommandFactory.js +108 -5
- package/dist/cli/parser.js +1 -1
- package/dist/client/auth/AuthProviderFactory.js +111 -0
- package/dist/client/auth/AuthProviderRegistry.js +190 -0
- package/dist/client/auth/RequestContext.js +78 -0
- package/dist/client/auth/accountPool.js +178 -0
- package/dist/client/auth/authContext.js +314 -0
- package/dist/client/auth/errors.js +39 -0
- package/dist/client/auth/index.js +61 -0
- package/dist/client/auth/middleware/AuthMiddleware.js +519 -0
- package/dist/client/auth/middleware/rateLimitByUser.js +554 -0
- package/dist/client/auth/providers/BaseAuthProvider.js +723 -0
- package/dist/client/auth/providers/CognitoProvider.js +304 -0
- package/dist/client/auth/providers/KeycloakProvider.js +393 -0
- package/dist/client/auth/providers/auth0.js +274 -0
- package/dist/client/auth/providers/betterAuth.js +182 -0
- package/dist/client/auth/providers/clerk.js +317 -0
- package/dist/client/auth/providers/custom.js +112 -0
- package/dist/client/auth/providers/firebase.js +226 -0
- package/dist/client/auth/providers/jwt.js +212 -0
- package/dist/client/auth/providers/oauth2.js +303 -0
- package/dist/client/auth/providers/supabase.js +259 -0
- package/dist/client/auth/providers/workos.js +284 -0
- package/dist/client/auth/serverBridge.js +25 -0
- package/dist/client/auth/sessionManager.js +437 -0
- package/dist/client/core/infrastructure/baseRegistry.js +5 -1
- package/dist/client/index.js +25 -0
- package/dist/client/mcp/toolRegistry.js +11 -1
- package/dist/client/neurolink.js +218 -0
- package/dist/client/rag/ChunkerRegistry.js +2 -2
- package/dist/client/rag/metadata/MetadataExtractorRegistry.js +2 -2
- package/dist/client/rag/reranker/RerankerRegistry.js +2 -2
- package/dist/client/server/routes/agentRoutes.js +20 -2
- package/dist/client/types/authTypes.js +2 -1
- package/dist/core/infrastructure/baseRegistry.d.ts +3 -1
- package/dist/core/infrastructure/baseRegistry.js +5 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +25 -0
- package/dist/lib/auth/AuthProviderFactory.d.ts +71 -0
- package/dist/lib/auth/AuthProviderFactory.js +112 -0
- package/dist/lib/auth/AuthProviderRegistry.d.ts +33 -0
- package/dist/lib/auth/AuthProviderRegistry.js +191 -0
- package/dist/lib/auth/RequestContext.d.ts +23 -0
- package/dist/lib/auth/RequestContext.js +79 -0
- package/dist/lib/auth/authContext.d.ts +198 -0
- package/dist/lib/auth/authContext.js +315 -0
- package/dist/lib/auth/errors.d.ts +63 -0
- package/dist/lib/auth/errors.js +40 -0
- package/dist/lib/auth/index.d.ts +20 -8
- package/dist/lib/auth/index.js +35 -7
- package/dist/lib/auth/middleware/AuthMiddleware.d.ts +181 -0
- package/dist/lib/auth/middleware/AuthMiddleware.js +520 -0
- package/dist/lib/auth/middleware/rateLimitByUser.d.ts +282 -0
- package/dist/lib/auth/middleware/rateLimitByUser.js +555 -0
- package/dist/lib/auth/providers/BaseAuthProvider.d.ts +259 -0
- package/dist/lib/auth/providers/BaseAuthProvider.js +724 -0
- package/dist/lib/auth/providers/CognitoProvider.d.ts +61 -0
- package/dist/lib/auth/providers/CognitoProvider.js +305 -0
- package/dist/lib/auth/providers/KeycloakProvider.d.ts +61 -0
- package/dist/lib/auth/providers/KeycloakProvider.js +394 -0
- package/dist/lib/auth/providers/auth0.d.ts +59 -0
- package/dist/lib/auth/providers/auth0.js +275 -0
- package/dist/lib/auth/providers/betterAuth.d.ts +51 -0
- package/dist/lib/auth/providers/betterAuth.js +183 -0
- package/dist/lib/auth/providers/clerk.d.ts +65 -0
- package/dist/lib/auth/providers/clerk.js +318 -0
- package/dist/lib/auth/providers/custom.d.ts +64 -0
- package/dist/lib/auth/providers/custom.js +113 -0
- package/dist/lib/auth/providers/firebase.d.ts +63 -0
- package/dist/lib/auth/providers/firebase.js +227 -0
- package/dist/lib/auth/providers/jwt.d.ts +68 -0
- package/dist/lib/auth/providers/jwt.js +213 -0
- package/dist/lib/auth/providers/oauth2.d.ts +73 -0
- package/dist/lib/auth/providers/oauth2.js +304 -0
- package/dist/lib/auth/providers/supabase.d.ts +63 -0
- package/dist/lib/auth/providers/supabase.js +260 -0
- package/dist/lib/auth/providers/workos.d.ts +61 -0
- package/dist/lib/auth/providers/workos.js +285 -0
- package/dist/lib/auth/serverBridge.d.ts +14 -0
- package/dist/lib/auth/serverBridge.js +26 -0
- package/dist/lib/auth/sessionManager.d.ts +142 -0
- package/dist/lib/auth/sessionManager.js +438 -0
- package/dist/lib/core/infrastructure/baseRegistry.d.ts +3 -1
- package/dist/lib/core/infrastructure/baseRegistry.js +5 -1
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/index.js +25 -0
- package/dist/lib/mcp/toolRegistry.js +11 -1
- package/dist/lib/neurolink.d.ts +42 -1
- package/dist/lib/neurolink.js +218 -0
- package/dist/lib/rag/ChunkerRegistry.js +2 -2
- package/dist/lib/rag/metadata/MetadataExtractorRegistry.js +2 -2
- package/dist/lib/rag/reranker/RerankerRegistry.js +2 -2
- package/dist/lib/server/routes/agentRoutes.js +20 -2
- package/dist/lib/types/authTypes.d.ts +937 -1
- package/dist/lib/types/authTypes.js +2 -1
- package/dist/lib/types/configTypes.d.ts +46 -0
- package/dist/lib/types/generateTypes.d.ts +6 -0
- package/dist/lib/types/index.d.ts +1 -0
- package/dist/lib/types/streamTypes.d.ts +6 -0
- package/dist/mcp/toolRegistry.js +11 -1
- package/dist/neurolink.d.ts +42 -1
- package/dist/neurolink.js +218 -0
- package/dist/rag/ChunkerRegistry.js +2 -2
- package/dist/rag/metadata/MetadataExtractorRegistry.js +2 -2
- package/dist/rag/reranker/RerankerRegistry.js +2 -2
- package/dist/server/routes/agentRoutes.js +20 -2
- package/dist/types/authTypes.d.ts +937 -1
- package/dist/types/authTypes.js +2 -1
- package/dist/types/configTypes.d.ts +46 -0
- package/dist/types/generateTypes.d.ts +6 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/streamTypes.d.ts +6 -0
- package/package.json +2 -1
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
// src/lib/auth/providers/auth0.ts
|
|
2
|
+
import { BaseAuthProvider } from "./BaseAuthProvider.js";
|
|
3
|
+
import { AuthError } from "../errors.js";
|
|
4
|
+
import { logger } from "../../utils/logger.js";
|
|
5
|
+
import { createProxyFetch } from "../../proxy/proxyFetch.js";
|
|
6
|
+
import * as jose from "jose";
|
|
7
|
+
/**
|
|
8
|
+
* Auth0 Authentication Provider
|
|
9
|
+
*
|
|
10
|
+
* Supports JWT validation with JWKS for Auth0-issued tokens.
|
|
11
|
+
* Uses jose library for JWT verification against Auth0's JWKS endpoint.
|
|
12
|
+
*
|
|
13
|
+
* Features:
|
|
14
|
+
* - JWT validation with JWKS
|
|
15
|
+
* - User profile fetching (requires Management API token)
|
|
16
|
+
* - Role and permission extraction from token claims
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const auth0 = new Auth0Provider({
|
|
21
|
+
* type: "auth0",
|
|
22
|
+
* domain: "your-tenant.auth0.com",
|
|
23
|
+
* clientId: "your-client-id",
|
|
24
|
+
* audience: "https://your-api.example.com"
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* const result = await auth0.authenticateToken(bearerToken);
|
|
28
|
+
* if (result.valid) {
|
|
29
|
+
* console.log("Authenticated user:", result.user);
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export class Auth0Provider extends BaseAuthProvider {
|
|
34
|
+
type = "auth0";
|
|
35
|
+
domain;
|
|
36
|
+
clientId;
|
|
37
|
+
audience;
|
|
38
|
+
rolesNamespace;
|
|
39
|
+
permissionsNamespace;
|
|
40
|
+
jwks = null;
|
|
41
|
+
constructor(config) {
|
|
42
|
+
super(config);
|
|
43
|
+
if (!config.domain) {
|
|
44
|
+
throw AuthError.create("CONFIGURATION_ERROR", "Auth0 domain is required", { details: { missingFields: ["domain"] } });
|
|
45
|
+
}
|
|
46
|
+
if (!config.clientId) {
|
|
47
|
+
throw AuthError.create("CONFIGURATION_ERROR", "Auth0 clientId is required", { details: { missingFields: ["clientId"] } });
|
|
48
|
+
}
|
|
49
|
+
this.domain = config.domain;
|
|
50
|
+
this.clientId = config.clientId;
|
|
51
|
+
this.audience = config.audience;
|
|
52
|
+
// Allow custom namespaces for roles/permissions claims.
|
|
53
|
+
// If no namespace is configured, fall back to standard "roles" / "permissions" claims.
|
|
54
|
+
this.rolesNamespace = config.options?.rolesNamespace;
|
|
55
|
+
this.permissionsNamespace = config.options?.permissionsNamespace;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Initialize JWKS for JWT verification
|
|
59
|
+
*/
|
|
60
|
+
async initialize() {
|
|
61
|
+
try {
|
|
62
|
+
const jwksUrl = new URL(`https://${this.domain}/.well-known/jwks.json`);
|
|
63
|
+
this.jwks = jose.createRemoteJWKSet(jwksUrl);
|
|
64
|
+
logger.debug(`Auth0 provider initialized for domain: ${this.domain}`);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
throw AuthError.create("PROVIDER_INIT_FAILED", "Failed to initialize Auth0 JWKS", { cause: error instanceof Error ? error : new Error(String(error)) });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Validate Auth0 JWT token
|
|
72
|
+
*/
|
|
73
|
+
async authenticateToken(token, _context) {
|
|
74
|
+
if (!this.jwks) {
|
|
75
|
+
await this.initialize();
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
if (!this.jwks) {
|
|
79
|
+
return {
|
|
80
|
+
valid: false,
|
|
81
|
+
error: "Auth0 JWKS not initialized",
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const { payload } = await jose.jwtVerify(token, this.jwks, {
|
|
85
|
+
issuer: `https://${this.domain}/`,
|
|
86
|
+
audience: this.audience,
|
|
87
|
+
});
|
|
88
|
+
const auth0Payload = payload;
|
|
89
|
+
// Validate audience / authorized party against clientId
|
|
90
|
+
if (this.audience) {
|
|
91
|
+
const aud = auth0Payload.aud;
|
|
92
|
+
const audArray = Array.isArray(aud) ? aud : [aud];
|
|
93
|
+
if (!audArray.includes(this.audience)) {
|
|
94
|
+
return {
|
|
95
|
+
valid: false,
|
|
96
|
+
error: `Token audience does not match expected audience: ${this.audience}`,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (this.clientId) {
|
|
101
|
+
const aud = auth0Payload.aud;
|
|
102
|
+
const azp = payload.azp;
|
|
103
|
+
const audArray = Array.isArray(aud) ? aud : [aud];
|
|
104
|
+
if (azp) {
|
|
105
|
+
if (azp !== this.clientId) {
|
|
106
|
+
return {
|
|
107
|
+
valid: false,
|
|
108
|
+
error: `Token azp claim "${azp}" does not match clientId "${this.clientId}"`,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else if (!audArray.includes(this.clientId)) {
|
|
113
|
+
return {
|
|
114
|
+
valid: false,
|
|
115
|
+
error: `Token audience does not include clientId "${this.clientId}"`,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Extract roles: use custom namespace if configured, otherwise standard "roles" claim
|
|
120
|
+
const rolesKey = this.rolesNamespace ?? "roles";
|
|
121
|
+
const permissionsKey = this.permissionsNamespace ?? "permissions";
|
|
122
|
+
const roles = payload[rolesKey] || auth0Payload.roles || [];
|
|
123
|
+
const permissions = payload[permissionsKey] || auth0Payload.permissions || [];
|
|
124
|
+
// Extract user information from token
|
|
125
|
+
const user = {
|
|
126
|
+
id: auth0Payload.sub,
|
|
127
|
+
email: auth0Payload.email,
|
|
128
|
+
name: auth0Payload.name,
|
|
129
|
+
picture: auth0Payload.picture,
|
|
130
|
+
emailVerified: auth0Payload.email_verified,
|
|
131
|
+
roles,
|
|
132
|
+
permissions,
|
|
133
|
+
metadata: {
|
|
134
|
+
iss: auth0Payload.iss,
|
|
135
|
+
aud: auth0Payload.aud,
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
return {
|
|
139
|
+
valid: true,
|
|
140
|
+
payload: payload,
|
|
141
|
+
user,
|
|
142
|
+
expiresAt: new Date(auth0Payload.exp * 1000),
|
|
143
|
+
tokenType: "jwt",
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
148
|
+
logger.warn("Auth0 token validation failed:", message);
|
|
149
|
+
return {
|
|
150
|
+
valid: false,
|
|
151
|
+
error: message,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Fetch user profile from Auth0 Management API
|
|
157
|
+
* Note: Requires AUTH0_MANAGEMENT_TOKEN environment variable
|
|
158
|
+
*/
|
|
159
|
+
async getUser(userId) {
|
|
160
|
+
const managementToken = process.env.AUTH0_MANAGEMENT_TOKEN;
|
|
161
|
+
if (!managementToken) {
|
|
162
|
+
logger.warn("AUTH0_MANAGEMENT_TOKEN not set, cannot fetch user profile");
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
const proxyFetch = createProxyFetch();
|
|
167
|
+
const response = await proxyFetch(`https://${this.domain}/api/v2/users/${encodeURIComponent(userId)}`, {
|
|
168
|
+
headers: {
|
|
169
|
+
Authorization: `Bearer ${managementToken}`,
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
if (!response.ok) {
|
|
173
|
+
if (response.status === 404) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
throw AuthError.create("PROVIDER_ERROR", `Auth0 API returned ${response.status}`, { details: { statusCode: response.status } });
|
|
177
|
+
}
|
|
178
|
+
const data = (await response.json());
|
|
179
|
+
return {
|
|
180
|
+
id: data.user_id,
|
|
181
|
+
email: data.email,
|
|
182
|
+
name: data.name,
|
|
183
|
+
picture: data.picture,
|
|
184
|
+
emailVerified: data.email_verified,
|
|
185
|
+
roles: data.app_metadata?.roles ||
|
|
186
|
+
[],
|
|
187
|
+
permissions: data.app_metadata
|
|
188
|
+
?.permissions || [],
|
|
189
|
+
createdAt: data.created_at
|
|
190
|
+
? new Date(data.created_at)
|
|
191
|
+
: undefined,
|
|
192
|
+
lastLoginAt: data.last_login
|
|
193
|
+
? new Date(data.last_login)
|
|
194
|
+
: undefined,
|
|
195
|
+
metadata: data.user_metadata,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
logger.error("Failed to fetch Auth0 user:", error);
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Get user by email from Auth0 Management API
|
|
205
|
+
*/
|
|
206
|
+
async getUserByEmail(email) {
|
|
207
|
+
const managementToken = process.env.AUTH0_MANAGEMENT_TOKEN;
|
|
208
|
+
if (!managementToken) {
|
|
209
|
+
logger.warn("AUTH0_MANAGEMENT_TOKEN not set, cannot fetch user by email");
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
const proxyFetch = createProxyFetch();
|
|
214
|
+
const response = await proxyFetch(`https://${this.domain}/api/v2/users-by-email?email=${encodeURIComponent(email)}`, {
|
|
215
|
+
headers: {
|
|
216
|
+
Authorization: `Bearer ${managementToken}`,
|
|
217
|
+
},
|
|
218
|
+
});
|
|
219
|
+
if (!response.ok) {
|
|
220
|
+
throw AuthError.create("PROVIDER_ERROR", `Auth0 API returned ${response.status}`, { details: { statusCode: response.status } });
|
|
221
|
+
}
|
|
222
|
+
const users = (await response.json());
|
|
223
|
+
if (users.length === 0) {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
const data = users[0];
|
|
227
|
+
return {
|
|
228
|
+
id: data.user_id,
|
|
229
|
+
email: data.email,
|
|
230
|
+
name: data.name,
|
|
231
|
+
picture: data.picture,
|
|
232
|
+
emailVerified: data.email_verified,
|
|
233
|
+
roles: data.app_metadata?.roles ||
|
|
234
|
+
[],
|
|
235
|
+
permissions: data.app_metadata
|
|
236
|
+
?.permissions || [],
|
|
237
|
+
createdAt: data.created_at
|
|
238
|
+
? new Date(data.created_at)
|
|
239
|
+
: undefined,
|
|
240
|
+
lastLoginAt: data.last_login
|
|
241
|
+
? new Date(data.last_login)
|
|
242
|
+
: undefined,
|
|
243
|
+
metadata: data.user_metadata,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
logger.error("Failed to fetch Auth0 user by email:", error);
|
|
248
|
+
throw error;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Health check
|
|
253
|
+
*/
|
|
254
|
+
async healthCheck() {
|
|
255
|
+
try {
|
|
256
|
+
const proxyFetch = createProxyFetch();
|
|
257
|
+
const response = await proxyFetch(`https://${this.domain}/.well-known/openid-configuration`);
|
|
258
|
+
return {
|
|
259
|
+
healthy: response.ok,
|
|
260
|
+
providerConnected: response.ok,
|
|
261
|
+
sessionStorageHealthy: true,
|
|
262
|
+
error: response.ok ? undefined : `HTTP ${response.status}`,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
return {
|
|
267
|
+
healthy: false,
|
|
268
|
+
providerConnected: false,
|
|
269
|
+
sessionStorageHealthy: true,
|
|
270
|
+
error: error instanceof Error ? error.message : String(error),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=auth0.js.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { AuthProviderConfig, BetterAuthConfig, TokenValidationResult, AuthRequestContext, AuthHealthCheck } from "../../types/authTypes.js";
|
|
2
|
+
import { BaseAuthProvider } from "./BaseAuthProvider.js";
|
|
3
|
+
/**
|
|
4
|
+
* Better Auth Provider
|
|
5
|
+
*
|
|
6
|
+
* Supports Better Auth, a self-hosted open-source authentication solution.
|
|
7
|
+
* Validates session tokens and JWTs issued by Better Auth server.
|
|
8
|
+
*
|
|
9
|
+
* Features:
|
|
10
|
+
* - JWT validation using HMAC secret
|
|
11
|
+
* - Session validation via Better Auth API
|
|
12
|
+
* - Social provider support (GitHub, Google, Discord)
|
|
13
|
+
* - Session management (inherited from BaseAuthProvider)
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const betterAuth = new BetterAuthProvider({
|
|
18
|
+
* type: "better-auth",
|
|
19
|
+
* secret: "your-better-auth-secret",
|
|
20
|
+
* baseUrl: "https://your-app.com"
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* const result = await betterAuth.authenticateToken(sessionToken);
|
|
24
|
+
* if (result.valid) {
|
|
25
|
+
* console.log("Authenticated user:", result.user);
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare class BetterAuthProvider extends BaseAuthProvider {
|
|
30
|
+
readonly type: "better-auth";
|
|
31
|
+
private secret;
|
|
32
|
+
private baseUrl;
|
|
33
|
+
private secretKey;
|
|
34
|
+
constructor(config: AuthProviderConfig & BetterAuthConfig);
|
|
35
|
+
/**
|
|
36
|
+
* Validate Better Auth token (session or JWT)
|
|
37
|
+
*/
|
|
38
|
+
authenticateToken(token: string, _context?: AuthRequestContext): Promise<TokenValidationResult>;
|
|
39
|
+
/**
|
|
40
|
+
* Validate JWT using the secret
|
|
41
|
+
*/
|
|
42
|
+
private validateJWT;
|
|
43
|
+
/**
|
|
44
|
+
* Validate session via Better Auth API
|
|
45
|
+
*/
|
|
46
|
+
private validateSessionViaAPI;
|
|
47
|
+
/**
|
|
48
|
+
* Health check
|
|
49
|
+
*/
|
|
50
|
+
healthCheck(): Promise<AuthHealthCheck>;
|
|
51
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
// src/lib/auth/providers/betterAuth.ts
|
|
2
|
+
import { createProxyFetch } from "../../proxy/proxyFetch.js";
|
|
3
|
+
import { AuthError } from "../errors.js";
|
|
4
|
+
import * as jose from "jose";
|
|
5
|
+
import { BaseAuthProvider } from "./BaseAuthProvider.js";
|
|
6
|
+
/**
|
|
7
|
+
* Better Auth Provider
|
|
8
|
+
*
|
|
9
|
+
* Supports Better Auth, a self-hosted open-source authentication solution.
|
|
10
|
+
* Validates session tokens and JWTs issued by Better Auth server.
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - JWT validation using HMAC secret
|
|
14
|
+
* - Session validation via Better Auth API
|
|
15
|
+
* - Social provider support (GitHub, Google, Discord)
|
|
16
|
+
* - Session management (inherited from BaseAuthProvider)
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const betterAuth = new BetterAuthProvider({
|
|
21
|
+
* type: "better-auth",
|
|
22
|
+
* secret: "your-better-auth-secret",
|
|
23
|
+
* baseUrl: "https://your-app.com"
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* const result = await betterAuth.authenticateToken(sessionToken);
|
|
27
|
+
* if (result.valid) {
|
|
28
|
+
* console.log("Authenticated user:", result.user);
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export class BetterAuthProvider extends BaseAuthProvider {
|
|
33
|
+
type = "better-auth";
|
|
34
|
+
secret;
|
|
35
|
+
baseUrl;
|
|
36
|
+
secretKey;
|
|
37
|
+
constructor(config) {
|
|
38
|
+
super(config);
|
|
39
|
+
if (!config.secret) {
|
|
40
|
+
throw AuthError.create("CONFIGURATION_ERROR", "Better Auth secret is required", { details: { provider: "better-auth", missingFields: ["secret"] } });
|
|
41
|
+
}
|
|
42
|
+
if (!config.baseUrl) {
|
|
43
|
+
throw AuthError.create("CONFIGURATION_ERROR", "Better Auth baseUrl is required", { details: { provider: "better-auth", missingFields: ["baseUrl"] } });
|
|
44
|
+
}
|
|
45
|
+
this.secret = config.secret;
|
|
46
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, ""); // Remove trailing slash
|
|
47
|
+
this.secretKey = new TextEncoder().encode(this.secret);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Validate Better Auth token (session or JWT)
|
|
51
|
+
*/
|
|
52
|
+
async authenticateToken(token, _context) {
|
|
53
|
+
// Try JWT validation first (if it looks like a JWT)
|
|
54
|
+
if (token.includes(".") && token.split(".").length === 3) {
|
|
55
|
+
const jwtResult = await this.validateJWT(token);
|
|
56
|
+
if (jwtResult.valid) {
|
|
57
|
+
return jwtResult;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Fall back to session validation via API
|
|
61
|
+
return this.validateSessionViaAPI(token);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Validate JWT using the secret
|
|
65
|
+
*/
|
|
66
|
+
async validateJWT(token) {
|
|
67
|
+
try {
|
|
68
|
+
const { payload } = await jose.jwtVerify(token, this.secretKey);
|
|
69
|
+
if (!payload.sub) {
|
|
70
|
+
return {
|
|
71
|
+
valid: false,
|
|
72
|
+
error: "Token missing required 'sub' claim",
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const user = {
|
|
76
|
+
id: payload.sub,
|
|
77
|
+
email: payload.email,
|
|
78
|
+
name: payload.name,
|
|
79
|
+
picture: payload.picture,
|
|
80
|
+
emailVerified: payload.email_verified,
|
|
81
|
+
roles: payload.roles || [],
|
|
82
|
+
permissions: payload.permissions || [],
|
|
83
|
+
metadata: payload.metadata,
|
|
84
|
+
};
|
|
85
|
+
return {
|
|
86
|
+
valid: true,
|
|
87
|
+
payload: payload,
|
|
88
|
+
user,
|
|
89
|
+
expiresAt: payload.exp ? new Date(payload.exp * 1000) : undefined,
|
|
90
|
+
tokenType: "jwt",
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
return {
|
|
95
|
+
valid: false,
|
|
96
|
+
error: error instanceof Error ? error.message : String(error),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Validate session via Better Auth API
|
|
102
|
+
*/
|
|
103
|
+
async validateSessionViaAPI(sessionToken) {
|
|
104
|
+
try {
|
|
105
|
+
const proxyFetch = createProxyFetch();
|
|
106
|
+
const response = await proxyFetch(`${this.baseUrl}/api/auth/session`, {
|
|
107
|
+
headers: {
|
|
108
|
+
Cookie: `better-auth.session_token=${sessionToken}`,
|
|
109
|
+
},
|
|
110
|
+
signal: AbortSignal.timeout(5000),
|
|
111
|
+
});
|
|
112
|
+
if (!response.ok) {
|
|
113
|
+
return {
|
|
114
|
+
valid: false,
|
|
115
|
+
error: `Session validation failed: HTTP ${response.status}`,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const session = (await response.json());
|
|
119
|
+
if (!session.user) {
|
|
120
|
+
return {
|
|
121
|
+
valid: false,
|
|
122
|
+
error: "Invalid session",
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
const user = {
|
|
126
|
+
id: session.user.id,
|
|
127
|
+
email: session.user.email,
|
|
128
|
+
name: session.user.name,
|
|
129
|
+
picture: session.user.image,
|
|
130
|
+
emailVerified: session.user.emailVerified,
|
|
131
|
+
roles: session.user.roles || [],
|
|
132
|
+
permissions: session.user.permissions || [],
|
|
133
|
+
createdAt: session.user.createdAt
|
|
134
|
+
? new Date(session.user.createdAt)
|
|
135
|
+
: undefined,
|
|
136
|
+
metadata: session.user,
|
|
137
|
+
};
|
|
138
|
+
return {
|
|
139
|
+
valid: true,
|
|
140
|
+
payload: session,
|
|
141
|
+
user,
|
|
142
|
+
expiresAt: session.session?.expiresAt
|
|
143
|
+
? new Date(session.session.expiresAt)
|
|
144
|
+
: undefined,
|
|
145
|
+
tokenType: "session",
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
return {
|
|
150
|
+
valid: false,
|
|
151
|
+
error: error instanceof Error ? error.message : String(error),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Health check
|
|
157
|
+
*/
|
|
158
|
+
async healthCheck() {
|
|
159
|
+
try {
|
|
160
|
+
const proxyFetch = createProxyFetch();
|
|
161
|
+
// Better Auth typically exposes session endpoint that we can check
|
|
162
|
+
const response = await proxyFetch(`${this.baseUrl}/api/auth/session`, {
|
|
163
|
+
signal: AbortSignal.timeout(5000),
|
|
164
|
+
});
|
|
165
|
+
// Even a 401 means the endpoint is working
|
|
166
|
+
const isReachable = response.status < 500;
|
|
167
|
+
return {
|
|
168
|
+
healthy: isReachable,
|
|
169
|
+
providerConnected: isReachable,
|
|
170
|
+
sessionStorageHealthy: true,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
return {
|
|
175
|
+
healthy: false,
|
|
176
|
+
providerConnected: false,
|
|
177
|
+
sessionStorageHealthy: true,
|
|
178
|
+
error: error instanceof Error ? error.message : String(error),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=betterAuth.js.map
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { BaseAuthProvider } from "./BaseAuthProvider.js";
|
|
2
|
+
import type { AuthProviderConfig, ClerkConfig, AuthUser, TokenValidationResult, AuthRequestContext, AuthHealthCheck, AuthProviderType } from "../../types/authTypes.js";
|
|
3
|
+
/**
|
|
4
|
+
* Clerk Authentication Provider
|
|
5
|
+
*
|
|
6
|
+
* Supports Clerk's session-based and JWT authentication.
|
|
7
|
+
* Can validate both JWT tokens and session tokens via Clerk API.
|
|
8
|
+
*
|
|
9
|
+
* Features:
|
|
10
|
+
* - JWT validation using Clerk's JWKS
|
|
11
|
+
* - Session token validation via Clerk API
|
|
12
|
+
* - User profile fetching
|
|
13
|
+
* - Organization support for multi-tenant apps
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const clerk = new ClerkProvider({
|
|
18
|
+
* type: "clerk",
|
|
19
|
+
* publishableKey: "pk_test_...",
|
|
20
|
+
* secretKey: "sk_test_..."
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* const result = await clerk.authenticateToken(sessionToken);
|
|
24
|
+
* if (result.valid) {
|
|
25
|
+
* console.log("Authenticated user:", result.user);
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare class ClerkProvider extends BaseAuthProvider {
|
|
30
|
+
readonly type: AuthProviderType;
|
|
31
|
+
private secretKey;
|
|
32
|
+
private jwtKey?;
|
|
33
|
+
private publishableKey?;
|
|
34
|
+
private jwks;
|
|
35
|
+
private localKey;
|
|
36
|
+
constructor(config: AuthProviderConfig & ClerkConfig);
|
|
37
|
+
/**
|
|
38
|
+
* Initialize Clerk JWKS
|
|
39
|
+
*/
|
|
40
|
+
initialize(): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Validate Clerk session token or JWT
|
|
43
|
+
*/
|
|
44
|
+
authenticateToken(token: string, _context?: AuthRequestContext): Promise<TokenValidationResult>;
|
|
45
|
+
/**
|
|
46
|
+
* Validate JWT using local jwtKey (if configured) or JWKS
|
|
47
|
+
*/
|
|
48
|
+
private validateJWT;
|
|
49
|
+
/**
|
|
50
|
+
* Validate session token via Clerk API
|
|
51
|
+
*/
|
|
52
|
+
private validateSessionToken;
|
|
53
|
+
/**
|
|
54
|
+
* Get user by ID from Clerk API
|
|
55
|
+
*/
|
|
56
|
+
getUser(userId: string): Promise<AuthUser | null>;
|
|
57
|
+
/**
|
|
58
|
+
* Get user by email from Clerk API
|
|
59
|
+
*/
|
|
60
|
+
getUserByEmail(email: string): Promise<AuthUser | null>;
|
|
61
|
+
/**
|
|
62
|
+
* Health check
|
|
63
|
+
*/
|
|
64
|
+
healthCheck(): Promise<AuthHealthCheck>;
|
|
65
|
+
}
|