@55387.ai/uniauth-server 1.2.3 → 1.2.4

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
@@ -162,6 +162,24 @@ try {
162
162
  }
163
163
  ```
164
164
 
165
+ ## 🤖 AI Agent Prompts / AI 智能体提示词
166
+
167
+ This package includes an AI-ready integration prompt. Copy it into your AI coding assistant (Claude, Cursor, Copilot, etc.) to generate a complete backend protection setup automatically.
168
+
169
+ 本包附带 AI 集成提示词。将其复制到 AI 编程助手中,即可自动生成完整的后端保护代码。
170
+
171
+ ```bash
172
+ # After install, find the prompt at:
173
+ # 安装后,提示词文件位于:
174
+ cat node_modules/@55387.ai/uniauth-server/ai-prompts/backend-protection.md
175
+ ```
176
+
177
+ > [!TIP]
178
+ > Replace placeholders like `YOUR_UNIAUTH_URL` and `YOUR_CLIENT_SECRET` before pasting into your AI assistant.
179
+ > 粘贴到 AI 助手前,请替换 `YOUR_UNIAUTH_URL` 和 `YOUR_CLIENT_SECRET` 等占位符。
180
+
181
+ See all prompts: [docs/ai-prompts/](../../docs/ai-prompts/README.md)
182
+
165
183
  ## License
166
184
 
167
185
  MIT
@@ -0,0 +1,197 @@
1
+ # 🤖 AI Prompt: Backend API Protection
2
+
3
+ > Copy everything below the line and paste into your AI coding assistant.
4
+ >
5
+ > 复制下方分割线以下的全部内容,粘贴到你的 AI 编程助手中。
6
+
7
+ ---
8
+
9
+ You are an expert Node.js/TypeScript backend developer. Help me protect my API routes using UniAuth token verification with the official `@55387.ai/uniauth-server` SDK.
10
+
11
+ ## Project Context
12
+
13
+ - **UniAuth Server URL**: `YOUR_UNIAUTH_URL` (e.g. `https://auth.55387.xyz`)
14
+ - **Client ID**: `YOUR_CLIENT_ID`
15
+ - **Client Secret**: `YOUR_CLIENT_SECRET`
16
+ - **Framework**: Express / Hono / Next.js API Routes (choose based on my project)
17
+
18
+ ## SDK Reference
19
+
20
+ ### Installation
21
+
22
+ ```bash
23
+ npm install @55387.ai/uniauth-server
24
+ ```
25
+
26
+ ### UniAuthServer Class
27
+
28
+ ```typescript
29
+ import { UniAuthServer } from '@55387.ai/uniauth-server';
30
+
31
+ const auth = new UniAuthServer({
32
+ baseUrl: 'YOUR_UNIAUTH_URL',
33
+ clientId: 'YOUR_CLIENT_ID',
34
+ clientSecret: 'YOUR_CLIENT_SECRET',
35
+ jwtPublicKey: process.env.JWT_PUBLIC_KEY, // optional, for local verification
36
+ });
37
+ ```
38
+
39
+ ### Core Methods
40
+
41
+ ```typescript
42
+ // Verify an access token (remote → introspection → local JWT fallback)
43
+ const payload = await auth.verifyToken(accessToken);
44
+ // Returns: TokenPayload { sub, iss, aud, iat, exp, scope, azp, phone, email }
45
+
46
+ // Token introspection (RFC 7662)
47
+ const result = await auth.introspectToken(token, 'access_token');
48
+ // Returns: IntrospectionResult { active, scope, client_id, sub, exp, ... }
49
+
50
+ // Check if token is active
51
+ const isActive = await auth.isTokenActive(token);
52
+
53
+ // Get user info by ID
54
+ const user = await auth.getUser(userId);
55
+ // Returns: UserInfo { id, phone, email, nickname, avatar_url, ... }
56
+
57
+ // Cache management
58
+ auth.clearCache();
59
+ auth.getCacheStats(); // { size, entries }
60
+ ```
61
+
62
+ ### Express Middleware
63
+
64
+ ```typescript
65
+ import express from 'express';
66
+
67
+ const app = express();
68
+
69
+ // Protect all /api routes
70
+ app.use('/api/*', auth.middleware());
71
+
72
+ // Access user info in route handlers
73
+ app.get('/api/profile', (req, res) => {
74
+ // req.authPayload — TokenPayload (always available)
75
+ // req.user — UserInfo (fetched automatically, may be undefined)
76
+ res.json({ user: req.user, payload: req.authPayload });
77
+ });
78
+ ```
79
+
80
+ ### Hono Middleware
81
+
82
+ ```typescript
83
+ import { Hono } from 'hono';
84
+
85
+ const app = new Hono();
86
+
87
+ // Protect all /api routes
88
+ app.use('/api/*', auth.honoMiddleware());
89
+
90
+ // Access user info in route handlers
91
+ app.get('/api/profile', (c) => {
92
+ const user = c.get('user'); // UserInfo
93
+ const payload = c.get('authPayload'); // TokenPayload
94
+ return c.json({ user, payload });
95
+ });
96
+ ```
97
+
98
+ ### Next.js API Route Protection
99
+
100
+ ```typescript
101
+ // middleware.ts or in each API route
102
+ import { UniAuthServer } from '@55387.ai/uniauth-server';
103
+
104
+ const auth = new UniAuthServer({
105
+ baseUrl: process.env.UNIAUTH_URL!,
106
+ clientId: process.env.UNIAUTH_CLIENT_ID!,
107
+ clientSecret: process.env.UNIAUTH_CLIENT_SECRET!,
108
+ });
109
+
110
+ export async function protectRoute(req: Request) {
111
+ const authHeader = req.headers.get('authorization');
112
+ if (!authHeader?.startsWith('Bearer ')) {
113
+ return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401 });
114
+ }
115
+ const payload = await auth.verifyToken(authHeader.substring(7));
116
+ return payload; // Use in your handler
117
+ }
118
+ ```
119
+
120
+ ### Types
121
+
122
+ ```typescript
123
+ interface TokenPayload {
124
+ sub: string; // User ID or Client ID (for M2M tokens)
125
+ iss?: string; // Issuer
126
+ aud?: string | string[];
127
+ iat: number; // Issued at
128
+ exp: number; // Expiration
129
+ scope?: string; // Scopes (space-separated)
130
+ azp?: string; // Authorized party (client_id)
131
+ phone?: string;
132
+ email?: string;
133
+ }
134
+
135
+ interface UserInfo {
136
+ id: string;
137
+ phone?: string | null;
138
+ email?: string | null;
139
+ nickname?: string | null;
140
+ avatar_url?: string | null;
141
+ phone_verified?: boolean;
142
+ email_verified?: boolean;
143
+ created_at?: string;
144
+ updated_at?: string;
145
+ }
146
+
147
+ // Error handling
148
+ import { ServerAuthError, ServerErrorCode } from '@55387.ai/uniauth-server';
149
+
150
+ try {
151
+ await auth.verifyToken(token);
152
+ } catch (error) {
153
+ if (error instanceof ServerAuthError) {
154
+ // error.code: 'INVALID_TOKEN' | 'TOKEN_EXPIRED' | 'UNAUTHORIZED' | ...
155
+ // error.statusCode: 401
156
+ // error.message: human-readable message
157
+ }
158
+ }
159
+ ```
160
+
161
+ ### Error Codes
162
+
163
+ | Code | Meaning |
164
+ |------|---------|
165
+ | `INVALID_TOKEN` | Token is malformed or invalid |
166
+ | `TOKEN_EXPIRED` | Token has expired |
167
+ | `VERIFICATION_FAILED` | Remote verification failed |
168
+ | `USER_NOT_FOUND` | User ID from token not found |
169
+ | `UNAUTHORIZED` | Missing or invalid Authorization header |
170
+ | `NO_PUBLIC_KEY` | JWT public key not configured for local verification |
171
+ | `NETWORK_ERROR` | Cannot reach UniAuth server |
172
+
173
+ ## Requirements
174
+
175
+ 1. **Middleware Setup**: Configure `UniAuthServer` and apply middleware to protect API routes.
176
+
177
+ 2. **Public vs Protected**: Some routes should be public (e.g. health check, login). Apply middleware selectively.
178
+
179
+ 3. **Error Handling**: Return proper JSON error responses with appropriate HTTP status codes. Never expose internal errors.
180
+
181
+ 4. **M2M Support**: Handle both user tokens (`sub` = user ID) and machine-to-machine tokens (`sub` = client ID, no user info).
182
+
183
+ 5. **CORS**: Configure CORS to allow requests from your frontend origin with `Authorization` header.
184
+
185
+ 6. **Rate Limiting**: Add basic rate limiting to prevent abuse.
186
+
187
+ 7. **Environment Variables**:
188
+ ```env
189
+ UNIAUTH_URL=YOUR_UNIAUTH_URL
190
+ UNIAUTH_CLIENT_ID=YOUR_CLIENT_ID
191
+ UNIAUTH_CLIENT_SECRET=YOUR_CLIENT_SECRET
192
+ JWT_PUBLIC_KEY=optional_for_local_verification
193
+ ```
194
+
195
+ 8. **Testing**: Include unit tests using Vitest. Mock the `UniAuthServer` for testing.
196
+
197
+ Generate the complete implementation based on my project's framework.
package/dist/index.cjs CHANGED
@@ -113,6 +113,24 @@ var UniAuthServer = class {
113
113
  if (error instanceof ServerAuthError) {
114
114
  throw error;
115
115
  }
116
+ try {
117
+ const introspectionResult = await this.introspectToken(token);
118
+ if (introspectionResult.active) {
119
+ const payload = {
120
+ sub: introspectionResult.sub || "",
121
+ iss: introspectionResult.iss || "",
122
+ aud: introspectionResult.aud || "",
123
+ iat: introspectionResult.iat || 0,
124
+ exp: introspectionResult.exp || 0,
125
+ scope: introspectionResult.scope,
126
+ azp: introspectionResult.client_id
127
+ };
128
+ const cacheExpiry = Math.min(payload.exp * 1e3, Date.now() + 60 * 1e3);
129
+ this.tokenCache.set(token, { payload, expiresAt: cacheExpiry });
130
+ return payload;
131
+ }
132
+ } catch {
133
+ }
116
134
  if (this.config.jwtPublicKey) {
117
135
  return this.verifyTokenLocally(token);
118
136
  }
package/dist/index.js CHANGED
@@ -76,6 +76,24 @@ var UniAuthServer = class {
76
76
  if (error instanceof ServerAuthError) {
77
77
  throw error;
78
78
  }
79
+ try {
80
+ const introspectionResult = await this.introspectToken(token);
81
+ if (introspectionResult.active) {
82
+ const payload = {
83
+ sub: introspectionResult.sub || "",
84
+ iss: introspectionResult.iss || "",
85
+ aud: introspectionResult.aud || "",
86
+ iat: introspectionResult.iat || 0,
87
+ exp: introspectionResult.exp || 0,
88
+ scope: introspectionResult.scope,
89
+ azp: introspectionResult.client_id
90
+ };
91
+ const cacheExpiry = Math.min(payload.exp * 1e3, Date.now() + 60 * 1e3);
92
+ this.tokenCache.set(token, { payload, expiresAt: cacheExpiry });
93
+ return payload;
94
+ }
95
+ } catch {
96
+ }
79
97
  if (this.config.jwtPublicKey) {
80
98
  return this.verifyTokenLocally(token);
81
99
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@55387.ai/uniauth-server",
3
- "version": "1.2.3",
3
+ "version": "1.2.4",
4
4
  "description": "UniAuth Server SDK - Token verification for Node.js backends",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -8,7 +8,8 @@
8
8
  "types": "./dist/index.d.ts",
9
9
  "files": [
10
10
  "dist",
11
- "README.md"
11
+ "README.md",
12
+ "ai-prompts"
12
13
  ],
13
14
  "exports": {
14
15
  ".": {
@@ -44,4 +45,4 @@
44
45
  "jwt",
45
46
  "sdk"
46
47
  ]
47
- }
48
+ }