@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.
- package/LICENSE +21 -0
- package/README.md +321 -0
- package/dist/chunk-NALGJYQB.mjs +185 -0
- package/dist/chunk-YC7GFXAO.mjs +193 -0
- package/dist/cognito-GBSAAMZI.mjs +145 -0
- package/dist/cognito-VCVS77OX.mjs +145 -0
- package/dist/index.d.mts +121 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.js +384 -0
- package/dist/index.mjs +16 -0
- package/package.json +81 -0
|
@@ -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
|
+
};
|
package/dist/index.d.mts
ADDED
|
@@ -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 };
|