@leanmcp/auth 0.1.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.
@@ -0,0 +1,193 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
4
+ // src/index.ts
5
+ import "reflect-metadata";
6
+
7
+ // src/decorators.ts
8
+ import "reflect-metadata";
9
+ var AuthenticationError = class extends Error {
10
+ static {
11
+ __name(this, "AuthenticationError");
12
+ }
13
+ code;
14
+ constructor(message, code) {
15
+ super(message), this.code = code;
16
+ this.name = "AuthenticationError";
17
+ }
18
+ };
19
+ function Authenticated(authProvider) {
20
+ return function(target, propertyKey, descriptor) {
21
+ if (!propertyKey && !descriptor) {
22
+ Reflect.defineMetadata("auth:provider", authProvider, target);
23
+ Reflect.defineMetadata("auth:required", true, target);
24
+ const prototype = target.prototype;
25
+ const methodNames = Object.getOwnPropertyNames(prototype).filter((name) => name !== "constructor" && typeof prototype[name] === "function");
26
+ for (const methodName of methodNames) {
27
+ const originalDescriptor = Object.getOwnPropertyDescriptor(prototype, methodName);
28
+ if (originalDescriptor && typeof originalDescriptor.value === "function") {
29
+ const originalMethod = originalDescriptor.value;
30
+ Reflect.defineMetadata("auth:provider", authProvider, originalMethod);
31
+ Reflect.defineMetadata("auth:required", true, originalMethod);
32
+ prototype[methodName] = createAuthenticatedMethod(originalMethod, authProvider);
33
+ copyMetadata(originalMethod, prototype[methodName]);
34
+ }
35
+ }
36
+ return target;
37
+ }
38
+ if (descriptor && typeof descriptor.value === "function") {
39
+ const originalMethod = descriptor.value;
40
+ Reflect.defineMetadata("auth:provider", authProvider, originalMethod);
41
+ Reflect.defineMetadata("auth:required", true, originalMethod);
42
+ descriptor.value = createAuthenticatedMethod(originalMethod, authProvider);
43
+ copyMetadata(originalMethod, descriptor.value);
44
+ return descriptor;
45
+ }
46
+ throw new Error("@Authenticated can only be applied to classes or methods");
47
+ };
48
+ }
49
+ __name(Authenticated, "Authenticated");
50
+ function createAuthenticatedMethod(originalMethod, authProvider) {
51
+ return async function(...args) {
52
+ const firstArg = args[0];
53
+ let token;
54
+ let cleanedArgs = args;
55
+ if (firstArg && typeof firstArg === "object") {
56
+ token = firstArg.token;
57
+ const { token: _, ...restArgs } = firstArg;
58
+ cleanedArgs = [
59
+ restArgs,
60
+ ...args.slice(1)
61
+ ];
62
+ }
63
+ if (!token) {
64
+ throw new AuthenticationError("Authentication required. Please provide a valid token in the request.", "MISSING_TOKEN");
65
+ }
66
+ try {
67
+ const isValid = await authProvider.verifyToken(token);
68
+ if (!isValid) {
69
+ throw new AuthenticationError("Invalid or expired token. Please authenticate again.", "INVALID_TOKEN");
70
+ }
71
+ } catch (error) {
72
+ if (error instanceof AuthenticationError) {
73
+ throw error;
74
+ }
75
+ throw new AuthenticationError(`Token verification failed: ${error instanceof Error ? error.message : String(error)}`, "VERIFICATION_FAILED");
76
+ }
77
+ return originalMethod.apply(this, cleanedArgs);
78
+ };
79
+ }
80
+ __name(createAuthenticatedMethod, "createAuthenticatedMethod");
81
+ function copyMetadata(source, target) {
82
+ const metadataKeys = Reflect.getMetadataKeys(source);
83
+ for (const key of metadataKeys) {
84
+ const value = Reflect.getMetadata(key, source);
85
+ Reflect.defineMetadata(key, value, target);
86
+ }
87
+ const designKeys = [
88
+ "design:type",
89
+ "design:paramtypes",
90
+ "design:returntype"
91
+ ];
92
+ for (const key of designKeys) {
93
+ const value = Reflect.getMetadata(key, source);
94
+ if (value !== void 0) {
95
+ Reflect.defineMetadata(key, value, target);
96
+ }
97
+ }
98
+ }
99
+ __name(copyMetadata, "copyMetadata");
100
+ function isAuthenticationRequired(target) {
101
+ return Reflect.getMetadata("auth:required", target) === true;
102
+ }
103
+ __name(isAuthenticationRequired, "isAuthenticationRequired");
104
+ function getAuthProvider(target) {
105
+ return Reflect.getMetadata("auth:provider", target);
106
+ }
107
+ __name(getAuthProvider, "getAuthProvider");
108
+
109
+ // src/index.ts
110
+ var AuthProviderBase = class {
111
+ static {
112
+ __name(this, "AuthProviderBase");
113
+ }
114
+ };
115
+ var AuthProvider = class extends AuthProviderBase {
116
+ static {
117
+ __name(this, "AuthProvider");
118
+ }
119
+ providerInstance = null;
120
+ providerType;
121
+ config;
122
+ constructor(provider, config) {
123
+ super();
124
+ this.providerType = provider.toLowerCase();
125
+ this.config = config;
126
+ }
127
+ /**
128
+ * Initialize the selected auth provider
129
+ */
130
+ async init(config) {
131
+ const finalConfig = config || this.config;
132
+ switch (this.providerType) {
133
+ case "cognito": {
134
+ const { AuthCognito } = await import("./cognito-GBSAAMZI.mjs");
135
+ this.providerInstance = new AuthCognito();
136
+ await this.providerInstance.init(finalConfig);
137
+ break;
138
+ }
139
+ // Add more providers here in the future
140
+ // case 'clerk': {
141
+ // const { AuthClerk } = await import('./providers/clerk');
142
+ // this.providerInstance = new AuthClerk();
143
+ // await this.providerInstance.init(finalConfig);
144
+ // break;
145
+ // }
146
+ default:
147
+ throw new Error(`Unsupported auth provider: ${this.providerType}. Supported providers: cognito`);
148
+ }
149
+ }
150
+ /**
151
+ * Refresh an authentication token
152
+ */
153
+ async refreshToken(refreshToken, username) {
154
+ if (!this.providerInstance) {
155
+ throw new Error("AuthProvider not initialized. Call init() first.");
156
+ }
157
+ return this.providerInstance.refreshToken(refreshToken, username);
158
+ }
159
+ /**
160
+ * Verify if a token is valid
161
+ */
162
+ async verifyToken(token) {
163
+ if (!this.providerInstance) {
164
+ throw new Error("AuthProvider not initialized. Call init() first.");
165
+ }
166
+ return this.providerInstance.verifyToken(token);
167
+ }
168
+ /**
169
+ * Get user information from a token
170
+ */
171
+ async getUser(token) {
172
+ if (!this.providerInstance) {
173
+ throw new Error("AuthProvider not initialized. Call init() first.");
174
+ }
175
+ return this.providerInstance.getUser(token);
176
+ }
177
+ /**
178
+ * Get the provider type
179
+ */
180
+ getProviderType() {
181
+ return this.providerType;
182
+ }
183
+ };
184
+
185
+ export {
186
+ __name,
187
+ AuthenticationError,
188
+ Authenticated,
189
+ isAuthenticationRequired,
190
+ getAuthProvider,
191
+ AuthProviderBase,
192
+ AuthProvider
193
+ };
@@ -0,0 +1,145 @@
1
+ import {
2
+ AuthProviderBase,
3
+ __name
4
+ } from "./chunk-YC7GFXAO.mjs";
5
+
6
+ // src/providers/cognito.ts
7
+ import { CognitoIdentityProviderClient, InitiateAuthCommand } from "@aws-sdk/client-cognito-identity-provider";
8
+ import { createHmac } from "crypto";
9
+ import axios from "axios";
10
+ import jwt from "jsonwebtoken";
11
+ import jwkToPem from "jwk-to-pem";
12
+ var AuthCognito = class extends AuthProviderBase {
13
+ static {
14
+ __name(this, "AuthCognito");
15
+ }
16
+ cognito = null;
17
+ region = "";
18
+ userPoolId = "";
19
+ clientId = "";
20
+ clientSecret = "";
21
+ jwksCache = null;
22
+ /**
23
+ * Initialize the Cognito client with configuration
24
+ */
25
+ async init(config) {
26
+ this.region = config?.region || process.env.AWS_REGION || "";
27
+ this.userPoolId = config?.userPoolId || process.env.COGNITO_USER_POOL_ID || "";
28
+ this.clientId = config?.clientId || process.env.COGNITO_CLIENT_ID || "";
29
+ this.clientSecret = config?.clientSecret || process.env.COGNITO_CLIENT_SECRET || "";
30
+ if (!this.region || !this.userPoolId || !this.clientId) {
31
+ throw new Error("Missing required Cognito configuration: region, userPoolId, and clientId are required");
32
+ }
33
+ this.cognito = new CognitoIdentityProviderClient({
34
+ region: this.region
35
+ });
36
+ }
37
+ /**
38
+ * Refresh access tokens using a refresh token
39
+ */
40
+ async refreshToken(refreshToken, username) {
41
+ if (!this.cognito) {
42
+ throw new Error("CognitoAuth not initialized. Call init() first.");
43
+ }
44
+ const authParameters = {
45
+ REFRESH_TOKEN: refreshToken
46
+ };
47
+ if (this.clientSecret) {
48
+ const usernameForHash = username;
49
+ const secretHash = this.calculateSecretHash(usernameForHash);
50
+ authParameters.SECRET_HASH = secretHash;
51
+ }
52
+ const command = new InitiateAuthCommand({
53
+ AuthFlow: "REFRESH_TOKEN_AUTH",
54
+ ClientId: this.clientId,
55
+ AuthParameters: authParameters
56
+ });
57
+ return await this.cognito.send(command);
58
+ }
59
+ /**
60
+ * Verify a Cognito JWT token using JWKS
61
+ */
62
+ async verifyToken(token) {
63
+ try {
64
+ await this.verifyJwt(token);
65
+ return true;
66
+ } catch (error) {
67
+ if (error instanceof Error) {
68
+ if (error.message.includes("jwt expired")) {
69
+ throw new Error("Token has expired");
70
+ } else if (error.message.includes("invalid signature")) {
71
+ throw new Error("Invalid token signature");
72
+ } else if (error.message.includes("jwt malformed")) {
73
+ throw new Error("Malformed token");
74
+ } else if (error.message.includes("invalid issuer")) {
75
+ throw new Error("Invalid token issuer");
76
+ }
77
+ throw error;
78
+ }
79
+ return false;
80
+ }
81
+ }
82
+ /**
83
+ * Get user information from an ID token
84
+ */
85
+ async getUser(idToken) {
86
+ const decoded = jwt.decode(idToken);
87
+ if (!decoded) {
88
+ throw new Error("Invalid ID token");
89
+ }
90
+ return {
91
+ username: decoded["cognito:username"],
92
+ email: decoded.email,
93
+ email_verified: decoded.email_verified,
94
+ sub: decoded.sub,
95
+ attributes: decoded
96
+ };
97
+ }
98
+ /**
99
+ * Fetch JWKS from Cognito (cached)
100
+ */
101
+ async fetchJWKS() {
102
+ if (!this.jwksCache) {
103
+ const jwksUri = `https://cognito-idp.${this.region}.amazonaws.com/${this.userPoolId}/.well-known/jwks.json`;
104
+ const { data } = await axios.get(jwksUri);
105
+ this.jwksCache = data.keys;
106
+ }
107
+ return this.jwksCache;
108
+ }
109
+ /**
110
+ * Verify JWT token using JWKS
111
+ */
112
+ async verifyJwt(token) {
113
+ const decoded = jwt.decode(token, {
114
+ complete: true
115
+ });
116
+ if (!decoded) {
117
+ throw new Error("Invalid token");
118
+ }
119
+ const jwks = await this.fetchJWKS();
120
+ const key = jwks.find((k) => k.kid === decoded.header.kid);
121
+ if (!key) {
122
+ throw new Error("Signing key not found in JWKS");
123
+ }
124
+ const pem = jwkToPem(key);
125
+ return jwt.verify(token, pem, {
126
+ algorithms: [
127
+ "RS256"
128
+ ],
129
+ issuer: `https://cognito-idp.${this.region}.amazonaws.com/${this.userPoolId}`
130
+ });
131
+ }
132
+ /**
133
+ * Calculate SECRET_HASH for Cognito authentication
134
+ * SECRET_HASH = Base64(HMAC_SHA256(username + clientId, clientSecret))
135
+ */
136
+ calculateSecretHash(username) {
137
+ const message = username + this.clientId;
138
+ const hmac = createHmac("sha256", this.clientSecret);
139
+ hmac.update(message);
140
+ return hmac.digest("base64");
141
+ }
142
+ };
143
+ export {
144
+ AuthCognito
145
+ };
@@ -0,0 +1,145 @@
1
+ import {
2
+ AuthProviderBase,
3
+ __name
4
+ } from "./chunk-NALGJYQB.mjs";
5
+
6
+ // src/providers/cognito.ts
7
+ import { CognitoIdentityProviderClient, InitiateAuthCommand } from "@aws-sdk/client-cognito-identity-provider";
8
+ import { createHmac } from "crypto";
9
+ import axios from "axios";
10
+ import jwt from "jsonwebtoken";
11
+ import jwkToPem from "jwk-to-pem";
12
+ var AuthCognito = class extends AuthProviderBase {
13
+ static {
14
+ __name(this, "AuthCognito");
15
+ }
16
+ cognito = null;
17
+ region = "";
18
+ userPoolId = "";
19
+ clientId = "";
20
+ clientSecret = "";
21
+ jwksCache = null;
22
+ /**
23
+ * Initialize the Cognito client with configuration
24
+ */
25
+ async init(config) {
26
+ this.region = config?.region || process.env.AWS_REGION || "";
27
+ this.userPoolId = config?.userPoolId || process.env.COGNITO_USER_POOL_ID || "";
28
+ this.clientId = config?.clientId || process.env.COGNITO_CLIENT_ID || "";
29
+ this.clientSecret = config?.clientSecret || process.env.COGNITO_CLIENT_SECRET || "";
30
+ if (!this.region || !this.userPoolId || !this.clientId) {
31
+ throw new Error("Missing required Cognito configuration: region, userPoolId, and clientId are required");
32
+ }
33
+ this.cognito = new CognitoIdentityProviderClient({
34
+ region: this.region
35
+ });
36
+ }
37
+ /**
38
+ * Refresh access tokens using a refresh token
39
+ */
40
+ async refreshToken(refreshToken, username) {
41
+ if (!this.cognito) {
42
+ throw new Error("CognitoAuth not initialized. Call init() first.");
43
+ }
44
+ const authParameters = {
45
+ REFRESH_TOKEN: refreshToken
46
+ };
47
+ if (this.clientSecret) {
48
+ const usernameForHash = username;
49
+ const secretHash = this.calculateSecretHash(usernameForHash);
50
+ authParameters.SECRET_HASH = secretHash;
51
+ }
52
+ const command = new InitiateAuthCommand({
53
+ AuthFlow: "REFRESH_TOKEN_AUTH",
54
+ ClientId: this.clientId,
55
+ AuthParameters: authParameters
56
+ });
57
+ return await this.cognito.send(command);
58
+ }
59
+ /**
60
+ * Verify a Cognito JWT token using JWKS
61
+ */
62
+ async verifyToken(token) {
63
+ try {
64
+ await this.verifyJwt(token);
65
+ return true;
66
+ } catch (error) {
67
+ if (error instanceof Error) {
68
+ if (error.message.includes("jwt expired")) {
69
+ throw new Error("Token has expired");
70
+ } else if (error.message.includes("invalid signature")) {
71
+ throw new Error("Invalid token signature");
72
+ } else if (error.message.includes("jwt malformed")) {
73
+ throw new Error("Malformed token");
74
+ } else if (error.message.includes("invalid issuer")) {
75
+ throw new Error("Invalid token issuer");
76
+ }
77
+ throw error;
78
+ }
79
+ return false;
80
+ }
81
+ }
82
+ /**
83
+ * Get user information from an ID token
84
+ */
85
+ async getUser(idToken) {
86
+ const decoded = jwt.decode(idToken);
87
+ if (!decoded) {
88
+ throw new Error("Invalid ID token");
89
+ }
90
+ return {
91
+ username: decoded["cognito:username"],
92
+ email: decoded.email,
93
+ email_verified: decoded.email_verified,
94
+ sub: decoded.sub,
95
+ attributes: decoded
96
+ };
97
+ }
98
+ /**
99
+ * Fetch JWKS from Cognito (cached)
100
+ */
101
+ async fetchJWKS() {
102
+ if (!this.jwksCache) {
103
+ const jwksUri = `https://cognito-idp.${this.region}.amazonaws.com/${this.userPoolId}/.well-known/jwks.json`;
104
+ const { data } = await axios.get(jwksUri);
105
+ this.jwksCache = data.keys;
106
+ }
107
+ return this.jwksCache;
108
+ }
109
+ /**
110
+ * Verify JWT token using JWKS
111
+ */
112
+ async verifyJwt(token) {
113
+ const decoded = jwt.decode(token, {
114
+ complete: true
115
+ });
116
+ if (!decoded) {
117
+ throw new Error("Invalid token");
118
+ }
119
+ const jwks = await this.fetchJWKS();
120
+ const key = jwks.find((k) => k.kid === decoded.header.kid);
121
+ if (!key) {
122
+ throw new Error("Signing key not found in JWKS");
123
+ }
124
+ const pem = jwkToPem(key);
125
+ return jwt.verify(token, pem, {
126
+ algorithms: [
127
+ "RS256"
128
+ ],
129
+ issuer: `https://cognito-idp.${this.region}.amazonaws.com/${this.userPoolId}`
130
+ });
131
+ }
132
+ /**
133
+ * Calculate SECRET_HASH for Cognito authentication
134
+ * SECRET_HASH = Base64(HMAC_SHA256(username + clientId, clientSecret))
135
+ */
136
+ calculateSecretHash(username) {
137
+ const message = username + this.clientId;
138
+ const hmac = createHmac("sha256", this.clientSecret);
139
+ hmac.update(message);
140
+ return hmac.digest("base64");
141
+ }
142
+ };
143
+ export {
144
+ AuthCognito
145
+ };
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Authentication error class for better error handling
3
+ */
4
+ declare class AuthenticationError extends Error {
5
+ code: string;
6
+ constructor(message: string, code: string);
7
+ }
8
+ /**
9
+ * Decorator to protect MCP tools, prompts, resources, or entire services with authentication
10
+ *
11
+ * Usage:
12
+ *
13
+ * 1. Protect individual methods:
14
+ * ```typescript
15
+ * @Tool({ description: 'Analyze sentiment' })
16
+ * @Authenticated(authProvider)
17
+ * async analyzeSentiment(args: AnalyzeSentimentInput): Promise<AnalyzeSentimentOutput> {
18
+ * // This method requires authentication
19
+ * }
20
+ * ```
21
+ *
22
+ * 2. Protect entire service (all tools/prompts/resources):
23
+ * ```typescript
24
+ * @Authenticated(authProvider)
25
+ * export class SentimentAnalysisService {
26
+ * @Tool({ description: 'Analyze sentiment' })
27
+ * async analyzeSentiment(args: AnalyzeSentimentInput) {
28
+ * // All methods in this service require authentication
29
+ * }
30
+ * }
31
+ * ```
32
+ *
33
+ * The decorator expects authentication token in the MCP request _meta field:
34
+ * ```json
35
+ * {
36
+ * "method": "tools/call",
37
+ * "params": {
38
+ * "name": "toolName",
39
+ * "arguments": { ...businessData },
40
+ * "_meta": {
41
+ * "authorization": {
42
+ * "type": "bearer",
43
+ * "token": "your-jwt-token"
44
+ * }
45
+ * }
46
+ * }
47
+ * }
48
+ * ```
49
+ *
50
+ * @param authProvider - Instance of AuthProviderBase to use for token verification
51
+ */
52
+ declare function Authenticated(authProvider: AuthProviderBase): (target: any, propertyKey?: string | symbol, descriptor?: PropertyDescriptor) => any;
53
+ /**
54
+ * Check if a method or class requires authentication
55
+ */
56
+ declare function isAuthenticationRequired(target: any): boolean;
57
+ /**
58
+ * Get the auth provider for a method or class
59
+ */
60
+ declare function getAuthProvider(target: any): AuthProviderBase | undefined;
61
+
62
+ /**
63
+ * @leanmcp/auth - Authentication Module
64
+ *
65
+ * This module provides a base class for implementing authentication providers for MCP tools.
66
+ * Extend AuthProviderBase to integrate with different auth providers (Clerk, Stripe, Firebase, etc.)
67
+ */
68
+ /**
69
+ * Base class for authentication providers
70
+ * Extend this class to implement integrations with different auth providers
71
+ */
72
+ declare abstract class AuthProviderBase {
73
+ /**
74
+ * Initialize the auth provider with configuration
75
+ */
76
+ abstract init(config?: any): Promise<void>;
77
+ /**
78
+ * Refresh an authentication token
79
+ */
80
+ abstract refreshToken(refreshToken: string, username?: string): Promise<any>;
81
+ /**
82
+ * Verify if a token is valid
83
+ */
84
+ abstract verifyToken(token: string): Promise<boolean>;
85
+ /**
86
+ * Get user information from a token
87
+ */
88
+ abstract getUser(token: string): Promise<any>;
89
+ }
90
+ /**
91
+ * Unified AuthProvider class that dynamically selects the appropriate auth provider
92
+ * based on the provider parameter
93
+ */
94
+ declare class AuthProvider extends AuthProviderBase {
95
+ private providerInstance;
96
+ private providerType;
97
+ private config;
98
+ constructor(provider: string, config?: any);
99
+ /**
100
+ * Initialize the selected auth provider
101
+ */
102
+ init(config?: any): Promise<void>;
103
+ /**
104
+ * Refresh an authentication token
105
+ */
106
+ refreshToken(refreshToken: string, username?: string): Promise<any>;
107
+ /**
108
+ * Verify if a token is valid
109
+ */
110
+ verifyToken(token: string): Promise<boolean>;
111
+ /**
112
+ * Get user information from a token
113
+ */
114
+ getUser(token: string): Promise<any>;
115
+ /**
116
+ * Get the provider type
117
+ */
118
+ getProviderType(): string;
119
+ }
120
+
121
+ export { AuthProvider, AuthProviderBase, Authenticated, AuthenticationError, getAuthProvider, isAuthenticationRequired };