@leanmcp/auth 0.4.3 → 0.4.4-alpha.6.6dae082

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 CHANGED
@@ -1,396 +1,410 @@
1
- <p align="center">
2
- <img
3
- src="https://raw.githubusercontent.com/LeanMCP/leanmcp-sdk/refs/heads/main/assets/logo.png"
4
- alt="LeanMCP Logo"
5
- width="400"
6
- />
7
- </p>
8
-
9
- <p align="center">
10
- <strong>@leanmcp/auth</strong><br/>
11
- Token-based authentication decorators and multi-provider support for MCP tools.
12
- </p>
13
-
14
- <p align="center">
15
- <a href="https://www.npmjs.com/package/@leanmcp/auth">
16
- <img src="https://img.shields.io/npm/v/@leanmcp/auth" alt="npm version" />
17
- </a>
18
- <a href="https://www.npmjs.com/package/@leanmcp/auth">
19
- <img src="https://img.shields.io/npm/dm/@leanmcp/auth" alt="npm downloads" />
20
- </a>
21
- <a href="https://docs.leanmcp.com/sdk/auth">
22
- <img src="https://img.shields.io/badge/Docs-leanmcp-0A66C2?" />
23
- </a>
24
- <a href="https://discord.com/invite/DsRcA3GwPy">
25
- <img src="https://img.shields.io/badge/Discord-Join-5865F2?logo=discord&logoColor=white" />
26
- </a>
27
- <a href="https://x.com/LeanMcp">
28
- <img src="https://img.shields.io/badge/@LeanMCP-f5f5f5?logo=x&logoColor=000000" />
29
- </a>
30
- </p>
31
-
32
- ## Features
33
-
34
- - **@Authenticated Decorator** — Protect tools, prompts, and resources with a simple decorator
35
- - **Multi-Provider Support** — AWS Cognito, Clerk, Auth0, and LeanMCP providers
36
- - **Automatic authUser** — Decoded user info injected as global `authUser` variable
37
- - **Concurrency Safe** — Uses AsyncLocalStorage for request-isolated context
38
- - **Method or Class-Level** — Apply to individual methods or entire services
39
- - **OAuth & Session Modes** — Support for both session-based and OAuth refresh token flows
40
-
41
- ## Installation
42
-
43
- ```bash
44
- npm install @leanmcp/auth @leanmcp/core
45
- ```
46
-
47
- ### Provider Dependencies
48
-
49
- **AWS Cognito:**
50
- ```bash
51
- npm install @aws-sdk/client-cognito-identity-provider axios jsonwebtoken jwk-to-pem
52
- ```
53
-
54
- **Clerk:**
55
- ```bash
56
- npm install axios jsonwebtoken jwk-to-pem
57
- ```
58
-
59
- **Auth0:**
60
- ```bash
61
- npm install axios jsonwebtoken jwk-to-pem
62
- ```
63
-
64
- ## Quick Start
65
-
66
- ### 1. Initialize Auth Provider
67
-
68
- ```typescript
69
- import { AuthProvider } from "@leanmcp/auth";
70
-
71
- const authProvider = new AuthProvider('cognito', {
72
- region: 'us-east-1',
73
- userPoolId: 'us-east-1_XXXXXXXXX',
74
- clientId: 'your-client-id'
75
- });
76
-
77
- await authProvider.init();
78
- ```
79
-
80
- ### 2. Protect Methods with @Authenticated
81
-
82
- ```typescript
83
- import { Tool } from "@leanmcp/core";
84
- import { Authenticated } from "@leanmcp/auth";
85
-
86
- export class SentimentService {
87
- @Tool({ description: 'Analyze sentiment (requires auth)' })
88
- @Authenticated(authProvider)
89
- async analyzeSentiment(input: { text: string }) {
90
- // authUser is automatically available with user info
91
- console.log('User ID:', authUser.sub);
92
- console.log('Email:', authUser.email);
93
-
94
- return {
95
- sentiment: 'positive',
96
- score: 0.8,
97
- analyzedBy: authUser.sub
98
- };
99
- }
100
-
101
- // Public method - no authentication
102
- @Tool({ description: 'Get categories (public)' })
103
- async getCategories() {
104
- return { categories: ['positive', 'negative', 'neutral'] };
105
- }
106
- }
107
- ```
108
-
109
- ### 3. Protect Entire Service
110
-
111
- ```typescript
112
- // All methods in this class require authentication
113
- @Authenticated(authProvider)
114
- export class SecureService {
115
- @Tool({ description: 'Protected tool' })
116
- async protectedTool(input: { data: string }) {
117
- // authUser is available in all methods
118
- return { data: input.data, userId: authUser.sub };
119
- }
120
- }
121
- ```
122
-
123
- ---
124
-
125
- ## The authUser Variable
126
-
127
- When using `@Authenticated`, a global `authUser` variable is automatically injected containing the decoded JWT payload:
128
-
129
- ```typescript
130
- @Tool({ description: 'Create post' })
131
- @Authenticated(authProvider)
132
- async createPost(input: { title: string, content: string }) {
133
- return {
134
- id: generateId(),
135
- title: input.title,
136
- content: input.content,
137
- authorId: authUser.sub,
138
- authorEmail: authUser.email
139
- };
140
- }
141
- ```
142
-
143
- ### Provider-Specific User Data
144
-
145
- **AWS Cognito:**
146
- ```typescript
147
- {
148
- sub: 'user-uuid',
149
- email: 'user@example.com',
150
- email_verified: true,
151
- 'cognito:username': 'username',
152
- 'cognito:groups': ['admin', 'users']
153
- }
154
- ```
155
-
156
- **Clerk:**
157
- ```typescript
158
- {
159
- sub: 'user_2abc123xyz',
160
- userId: 'user_2abc123xyz',
161
- email: 'user@example.com',
162
- firstName: 'John',
163
- lastName: 'Doe',
164
- imageUrl: 'https://img.clerk.com/...'
165
- }
166
- ```
167
-
168
- **Auth0:**
169
- ```typescript
170
- {
171
- sub: 'auth0|507f1f77bcf86cd799439011',
172
- email: 'user@example.com',
173
- email_verified: true,
174
- name: 'John Doe',
175
- picture: 'https://s.gravatar.com/avatar/...'
176
- }
177
- ```
178
-
179
- ### Controlling User Fetch
180
-
181
- ```typescript
182
- // Fetch user info (default)
183
- @Authenticated(authProvider, { getUser: true })
184
- async withUserInfo(input: any) {
185
- console.log(authUser); // User data available
186
- }
187
-
188
- // Only verify token, skip user fetch (faster)
189
- @Authenticated(authProvider, { getUser: false })
190
- async tokenOnlyValidation(input: any) {
191
- // authUser is undefined
192
- }
193
- ```
194
-
195
- ---
196
-
197
- ## Supported Providers
198
-
199
- ### AWS Cognito
200
-
201
- ```typescript
202
- const authProvider = new AuthProvider('cognito', {
203
- region: 'us-east-1',
204
- userPoolId: 'us-east-1_XXXXXXXXX',
205
- clientId: 'your-client-id'
206
- });
207
- await authProvider.init();
208
- ```
209
-
210
- **Environment Variables:**
211
- ```bash
212
- AWS_REGION=us-east-1
213
- COGNITO_USER_POOL_ID=us-east-1_XXXXXXXXX
214
- COGNITO_CLIENT_ID=your-client-id
215
- ```
216
-
217
- ### Clerk
218
-
219
- ```typescript
220
- // Session Mode (default)
221
- const authProvider = new AuthProvider('clerk', {
222
- frontendApi: 'your-frontend-api.clerk.accounts.dev',
223
- secretKey: 'sk_test_...'
224
- });
225
-
226
- // OAuth Mode (with refresh tokens)
227
- const authProvider = new AuthProvider('clerk', {
228
- frontendApi: 'your-frontend-api.clerk.accounts.dev',
229
- secretKey: 'sk_test_...',
230
- clientId: 'your-oauth-client-id',
231
- clientSecret: 'your-oauth-client-secret',
232
- redirectUri: 'https://yourapp.com/callback'
233
- });
234
-
235
- await authProvider.init();
236
- ```
237
-
238
- ### Auth0
239
-
240
- ```typescript
241
- const authProvider = new AuthProvider('auth0', {
242
- domain: 'your-tenant.auth0.com',
243
- clientId: 'your-client-id',
244
- clientSecret: 'your-client-secret',
245
- audience: 'https://your-api-identifier'
246
- });
247
- await authProvider.init();
248
- ```
249
-
250
- ### LeanMCP
251
-
252
- For LeanMCP platform deployments with user secrets support:
253
-
254
- ```typescript
255
- const authProvider = new AuthProvider('leanmcp', {
256
- apiKey: 'your-leanmcp-api-key'
257
- });
258
- await authProvider.init();
259
- ```
260
-
261
- ---
262
-
263
- ## Client Usage
264
-
265
- Authentication tokens are passed via the `_meta` field following MCP protocol standards:
266
-
267
- ```typescript
268
- await mcpClient.callTool({
269
- name: "analyzeSentiment",
270
- arguments: { text: "Hello world" },
271
- _meta: {
272
- authorization: {
273
- type: "bearer",
274
- token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
275
- }
276
- }
277
- });
278
- ```
279
-
280
- ---
281
-
282
- ## Error Handling
283
-
284
- ```typescript
285
- import { AuthenticationError } from "@leanmcp/auth";
286
-
287
- try {
288
- await service.protectedMethod({ text: "test" });
289
- } catch (error) {
290
- if (error instanceof AuthenticationError) {
291
- switch (error.code) {
292
- case 'MISSING_TOKEN':
293
- console.log('No token provided');
294
- break;
295
- case 'INVALID_TOKEN':
296
- console.log('Token is invalid or expired');
297
- break;
298
- case 'VERIFICATION_FAILED':
299
- console.log('Verification failed:', error.message);
300
- break;
301
- }
302
- }
303
- }
304
- ```
305
-
306
- ---
307
-
308
- ## API Reference
309
-
310
- ### AuthProvider
311
-
312
- ```typescript
313
- class AuthProvider {
314
- constructor(provider: string, config: any);
315
- async init(config?: any): Promise<void>;
316
- async verifyToken(token: string): Promise<boolean>;
317
- async refreshToken(refreshToken: string): Promise<any>;
318
- async getUser(token: string): Promise<any>;
319
- getProviderType(): string;
320
- }
321
- ```
322
-
323
- ### @Authenticated Decorator
324
-
325
- ```typescript
326
- function Authenticated(
327
- authProvider: AuthProvider,
328
- options?: AuthenticatedOptions
329
- ): ClassDecorator | MethodDecorator;
330
-
331
- interface AuthenticatedOptions {
332
- getUser?: boolean; // Default: true
333
- projectId?: string; // For LeanMCP user secrets
334
- }
335
- ```
336
-
337
- ### AuthenticationError
338
-
339
- ```typescript
340
- class AuthenticationError extends Error {
341
- code: 'MISSING_TOKEN' | 'INVALID_TOKEN' | 'VERIFICATION_FAILED';
342
- constructor(message: string, code: string);
343
- }
344
- ```
345
-
346
- ### Helper Functions
347
-
348
- ```typescript
349
- // Check if authentication is required
350
- function isAuthenticationRequired(target: any): boolean;
351
-
352
- // Get auth provider for method/class
353
- function getAuthProvider(target: any): AuthProviderBase | undefined;
354
-
355
- // Get current authenticated user
356
- function getAuthUser(): any;
357
- ```
358
-
359
- ---
360
-
361
- ## Best Practices
362
-
363
- ### Security
364
- - Always use HTTPS in production
365
- - Store tokens securely (keychain, encrypted storage)
366
- - Implement token refresh before expiration
367
- - Add rate limiting to protect against brute force
368
-
369
- ### Configuration
370
- - Use environment variables for credentials
371
- - Never hardcode secrets in code
372
- - Use `_meta` for auth, not business arguments
373
-
374
- ### Performance
375
- - Use `getUser: false` when you only need token validation
376
- - JWKS keys are cached automatically for performance
377
-
378
- ---
379
-
380
- ## Documentation
381
-
382
- - [Full Documentation](https://docs.leanmcp.com/sdk/auth)
383
-
384
- ## Related Packages
385
-
386
- - [@leanmcp/core](https://www.npmjs.com/package/@leanmcp/core) — Core decorators and server functionality
387
- - [@leanmcp/env-injection](https://www.npmjs.com/package/@leanmcp/env-injection) — Environment variable injection for user secrets
388
-
389
- ## Links
390
-
391
- - [GitHub Repository](https://github.com/LeanMCP/leanmcp-sdk)
392
- - [NPM Package](https://www.npmjs.com/package/@leanmcp/auth)
393
-
394
- ## License
395
-
396
- MIT
1
+ <p align="center">
2
+ <img
3
+ src="https://raw.githubusercontent.com/LeanMCP/leanmcp-sdk/refs/heads/main/assets/logo.png"
4
+ alt="LeanMCP Logo"
5
+ width="400"
6
+ />
7
+ </p>
8
+
9
+ <p align="center">
10
+ <strong>@leanmcp/auth</strong><br/>
11
+ Token-based authentication decorators and multi-provider support for MCP tools.
12
+ </p>
13
+
14
+ <p align="center">
15
+ <a href="https://www.npmjs.com/package/@leanmcp/auth">
16
+ <img src="https://img.shields.io/npm/v/@leanmcp/auth" alt="npm version" />
17
+ </a>
18
+ <a href="https://www.npmjs.com/package/@leanmcp/auth">
19
+ <img src="https://img.shields.io/npm/dm/@leanmcp/auth" alt="npm downloads" />
20
+ </a>
21
+ <a href="https://docs.leanmcp.com/sdk/auth">
22
+ <img src="https://img.shields.io/badge/Docs-leanmcp-0A66C2?" />
23
+ </a>
24
+ <a href="https://discord.com/invite/DsRcA3GwPy">
25
+ <img src="https://img.shields.io/badge/Discord-Join-5865F2?logo=discord&logoColor=white" />
26
+ </a>
27
+ <a href="https://x.com/LeanMcp">
28
+ <img src="https://img.shields.io/badge/@LeanMCP-f5f5f5?logo=x&logoColor=000000" />
29
+ </a>
30
+ <a href="https://leanmcp.com/">
31
+ <img src="https://img.shields.io/badge/Website-leanmcp-0A66C2?" />
32
+ </a>
33
+ <a href="https://deepwiki.com/LeanMCP/leanmcp-sdk"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
34
+ </p>
35
+
36
+ ## Features
37
+
38
+ - **@Authenticated Decorator** — Protect tools, prompts, and resources with a simple decorator
39
+ - **Multi-Provider Support** — AWS Cognito, Clerk, Auth0, and LeanMCP providers
40
+ - **Automatic authUser** — Decoded user info injected as global `authUser` variable
41
+ - **Concurrency Safe** — Uses AsyncLocalStorage for request-isolated context
42
+ - **Method or Class-Level** — Apply to individual methods or entire services
43
+ - **OAuth & Session Modes** — Support for both session-based and OAuth refresh token flows
44
+
45
+ ## Installation
46
+
47
+ ```bash
48
+ npm install @leanmcp/auth @leanmcp/core
49
+ ```
50
+
51
+ ### Provider Dependencies
52
+
53
+ **AWS Cognito:**
54
+
55
+ ```bash
56
+ npm install @aws-sdk/client-cognito-identity-provider axios jsonwebtoken jwk-to-pem
57
+ ```
58
+
59
+ **Clerk:**
60
+
61
+ ```bash
62
+ npm install axios jsonwebtoken jwk-to-pem
63
+ ```
64
+
65
+ **Auth0:**
66
+
67
+ ```bash
68
+ npm install axios jsonwebtoken jwk-to-pem
69
+ ```
70
+
71
+ ## Quick Start
72
+
73
+ ### 1. Initialize Auth Provider
74
+
75
+ ```typescript
76
+ import { AuthProvider } from '@leanmcp/auth';
77
+
78
+ const authProvider = new AuthProvider('cognito', {
79
+ region: 'us-east-1',
80
+ userPoolId: 'us-east-1_XXXXXXXXX',
81
+ clientId: 'your-client-id',
82
+ });
83
+
84
+ await authProvider.init();
85
+ ```
86
+
87
+ ### 2. Protect Methods with @Authenticated
88
+
89
+ ```typescript
90
+ import { Tool } from '@leanmcp/core';
91
+ import { Authenticated } from '@leanmcp/auth';
92
+
93
+ export class SentimentService {
94
+ @Tool({ description: 'Analyze sentiment (requires auth)' })
95
+ @Authenticated(authProvider)
96
+ async analyzeSentiment(input: { text: string }) {
97
+ // authUser is automatically available with user info
98
+ console.log('User ID:', authUser.sub);
99
+ console.log('Email:', authUser.email);
100
+
101
+ return {
102
+ sentiment: 'positive',
103
+ score: 0.8,
104
+ analyzedBy: authUser.sub,
105
+ };
106
+ }
107
+
108
+ // Public method - no authentication
109
+ @Tool({ description: 'Get categories (public)' })
110
+ async getCategories() {
111
+ return { categories: ['positive', 'negative', 'neutral'] };
112
+ }
113
+ }
114
+ ```
115
+
116
+ ### 3. Protect Entire Service
117
+
118
+ ```typescript
119
+ // All methods in this class require authentication
120
+ @Authenticated(authProvider)
121
+ export class SecureService {
122
+ @Tool({ description: 'Protected tool' })
123
+ async protectedTool(input: { data: string }) {
124
+ // authUser is available in all methods
125
+ return { data: input.data, userId: authUser.sub };
126
+ }
127
+ }
128
+ ```
129
+
130
+ ---
131
+
132
+ ## The authUser Variable
133
+
134
+ When using `@Authenticated`, a global `authUser` variable is automatically injected containing the decoded JWT payload:
135
+
136
+ ```typescript
137
+ @Tool({ description: 'Create post' })
138
+ @Authenticated(authProvider)
139
+ async createPost(input: { title: string, content: string }) {
140
+ return {
141
+ id: generateId(),
142
+ title: input.title,
143
+ content: input.content,
144
+ authorId: authUser.sub,
145
+ authorEmail: authUser.email
146
+ };
147
+ }
148
+ ```
149
+
150
+ ### Provider-Specific User Data
151
+
152
+ **AWS Cognito:**
153
+
154
+ ```typescript
155
+ {
156
+ sub: 'user-uuid',
157
+ email: 'user@example.com',
158
+ email_verified: true,
159
+ 'cognito:username': 'username',
160
+ 'cognito:groups': ['admin', 'users']
161
+ }
162
+ ```
163
+
164
+ **Clerk:**
165
+
166
+ ```typescript
167
+ {
168
+ sub: 'user_2abc123xyz',
169
+ userId: 'user_2abc123xyz',
170
+ email: 'user@example.com',
171
+ firstName: 'John',
172
+ lastName: 'Doe',
173
+ imageUrl: 'https://img.clerk.com/...'
174
+ }
175
+ ```
176
+
177
+ **Auth0:**
178
+
179
+ ```typescript
180
+ {
181
+ sub: 'auth0|507f1f77bcf86cd799439011',
182
+ email: 'user@example.com',
183
+ email_verified: true,
184
+ name: 'John Doe',
185
+ picture: 'https://s.gravatar.com/avatar/...'
186
+ }
187
+ ```
188
+
189
+ ### Controlling User Fetch
190
+
191
+ ```typescript
192
+ // Fetch user info (default)
193
+ @Authenticated(authProvider, { getUser: true })
194
+ async withUserInfo(input: any) {
195
+ console.log(authUser); // User data available
196
+ }
197
+
198
+ // Only verify token, skip user fetch (faster)
199
+ @Authenticated(authProvider, { getUser: false })
200
+ async tokenOnlyValidation(input: any) {
201
+ // authUser is undefined
202
+ }
203
+ ```
204
+
205
+ ---
206
+
207
+ ## Supported Providers
208
+
209
+ ### AWS Cognito
210
+
211
+ ```typescript
212
+ const authProvider = new AuthProvider('cognito', {
213
+ region: 'us-east-1',
214
+ userPoolId: 'us-east-1_XXXXXXXXX',
215
+ clientId: 'your-client-id',
216
+ });
217
+ await authProvider.init();
218
+ ```
219
+
220
+ **Environment Variables:**
221
+
222
+ ```bash
223
+ AWS_REGION=us-east-1
224
+ COGNITO_USER_POOL_ID=us-east-1_XXXXXXXXX
225
+ COGNITO_CLIENT_ID=your-client-id
226
+ ```
227
+
228
+ ### Clerk
229
+
230
+ ```typescript
231
+ // Session Mode (default)
232
+ const authProvider = new AuthProvider('clerk', {
233
+ frontendApi: 'your-frontend-api.clerk.accounts.dev',
234
+ secretKey: 'sk_test_...',
235
+ });
236
+
237
+ // OAuth Mode (with refresh tokens)
238
+ const authProvider = new AuthProvider('clerk', {
239
+ frontendApi: 'your-frontend-api.clerk.accounts.dev',
240
+ secretKey: 'sk_test_...',
241
+ clientId: 'your-oauth-client-id',
242
+ clientSecret: 'your-oauth-client-secret',
243
+ redirectUri: 'https://yourapp.com/callback',
244
+ });
245
+
246
+ await authProvider.init();
247
+ ```
248
+
249
+ ### Auth0
250
+
251
+ ```typescript
252
+ const authProvider = new AuthProvider('auth0', {
253
+ domain: 'your-tenant.auth0.com',
254
+ clientId: 'your-client-id',
255
+ clientSecret: 'your-client-secret',
256
+ audience: 'https://your-api-identifier',
257
+ });
258
+ await authProvider.init();
259
+ ```
260
+
261
+ ### LeanMCP
262
+
263
+ For LeanMCP platform deployments with user secrets support:
264
+
265
+ ```typescript
266
+ const authProvider = new AuthProvider('leanmcp', {
267
+ apiKey: 'your-leanmcp-api-key',
268
+ });
269
+ await authProvider.init();
270
+ ```
271
+
272
+ ---
273
+
274
+ ## Client Usage
275
+
276
+ Authentication tokens are passed via the `_meta` field following MCP protocol standards:
277
+
278
+ ```typescript
279
+ await mcpClient.callTool({
280
+ name: 'analyzeSentiment',
281
+ arguments: { text: 'Hello world' },
282
+ _meta: {
283
+ authorization: {
284
+ type: 'bearer',
285
+ token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
286
+ },
287
+ },
288
+ });
289
+ ```
290
+
291
+ ---
292
+
293
+ ## Error Handling
294
+
295
+ ```typescript
296
+ import { AuthenticationError } from '@leanmcp/auth';
297
+
298
+ try {
299
+ await service.protectedMethod({ text: 'test' });
300
+ } catch (error) {
301
+ if (error instanceof AuthenticationError) {
302
+ switch (error.code) {
303
+ case 'MISSING_TOKEN':
304
+ console.log('No token provided');
305
+ break;
306
+ case 'INVALID_TOKEN':
307
+ console.log('Token is invalid or expired');
308
+ break;
309
+ case 'VERIFICATION_FAILED':
310
+ console.log('Verification failed:', error.message);
311
+ break;
312
+ }
313
+ }
314
+ }
315
+ ```
316
+
317
+ ---
318
+
319
+ ## API Reference
320
+
321
+ ### AuthProvider
322
+
323
+ ```typescript
324
+ class AuthProvider {
325
+ constructor(provider: string, config: any);
326
+ async init(config?: any): Promise<void>;
327
+ async verifyToken(token: string): Promise<boolean>;
328
+ async refreshToken(refreshToken: string): Promise<any>;
329
+ async getUser(token: string): Promise<any>;
330
+ getProviderType(): string;
331
+ }
332
+ ```
333
+
334
+ ### @Authenticated Decorator
335
+
336
+ ```typescript
337
+ function Authenticated(
338
+ authProvider: AuthProvider,
339
+ options?: AuthenticatedOptions
340
+ ): ClassDecorator | MethodDecorator;
341
+
342
+ interface AuthenticatedOptions {
343
+ getUser?: boolean; // Default: true
344
+ projectId?: string; // For LeanMCP user secrets
345
+ }
346
+ ```
347
+
348
+ ### AuthenticationError
349
+
350
+ ```typescript
351
+ class AuthenticationError extends Error {
352
+ code: 'MISSING_TOKEN' | 'INVALID_TOKEN' | 'VERIFICATION_FAILED';
353
+ constructor(message: string, code: string);
354
+ }
355
+ ```
356
+
357
+ ### Helper Functions
358
+
359
+ ```typescript
360
+ // Check if authentication is required
361
+ function isAuthenticationRequired(target: any): boolean;
362
+
363
+ // Get auth provider for method/class
364
+ function getAuthProvider(target: any): AuthProviderBase | undefined;
365
+
366
+ // Get current authenticated user
367
+ function getAuthUser(): any;
368
+ ```
369
+
370
+ ---
371
+
372
+ ## Best Practices
373
+
374
+ ### Security
375
+
376
+ - Always use HTTPS in production
377
+ - Store tokens securely (keychain, encrypted storage)
378
+ - Implement token refresh before expiration
379
+ - Add rate limiting to protect against brute force
380
+
381
+ ### Configuration
382
+
383
+ - Use environment variables for credentials
384
+ - Never hardcode secrets in code
385
+ - Use `_meta` for auth, not business arguments
386
+
387
+ ### Performance
388
+
389
+ - Use `getUser: false` when you only need token validation
390
+ - JWKS keys are cached automatically for performance
391
+
392
+ ---
393
+
394
+ ## Documentation
395
+
396
+ - [Full Documentation](https://docs.leanmcp.com/sdk/auth)
397
+
398
+ ## Related Packages
399
+
400
+ - [@leanmcp/core](https://www.npmjs.com/package/@leanmcp/core) — Core decorators and server functionality
401
+ - [@leanmcp/env-injection](https://www.npmjs.com/package/@leanmcp/env-injection) — Environment variable injection for user secrets
402
+
403
+ ## Links
404
+
405
+ - [GitHub Repository](https://github.com/LeanMCP/leanmcp-sdk)
406
+ - [NPM Package](https://www.npmjs.com/package/@leanmcp/auth)
407
+
408
+ ## License
409
+
410
+ MIT