@easecation/iam-client 1.0.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/README.md +66 -0
- package/dist/IamClient.d.ts +69 -0
- package/dist/IamClient.d.ts.map +1 -0
- package/dist/IamClient.js +185 -0
- package/dist/IamClient.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware.d.ts +33 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +87 -0
- package/dist/middleware.js.map +1 -0
- package/dist/types.d.ts +95 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# @easecation/iam-client
|
|
2
|
+
|
|
3
|
+
IAM V2 client library for EaseCation services. Provides an API wrapper and an Express middleware for validating RS256 access tokens against IAM.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @easecation/iam-client
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { IamClient } from '@easecation/iam-client';
|
|
15
|
+
|
|
16
|
+
const client = new IamClient({
|
|
17
|
+
iamBaseUrl: 'http://localhost:8401',
|
|
18
|
+
clientId: '10007',
|
|
19
|
+
clientSecret: 'YOUR_CLIENT_SECRET',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Exchange OAuth code for access + refresh tokens
|
|
23
|
+
const tokens = await client.exchangeOAuthCode(code, redirectUri);
|
|
24
|
+
|
|
25
|
+
// Verify access token and fetch permissions
|
|
26
|
+
const verify = await client.verifyToken(tokens.access_token);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Express Middleware
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import express from 'express';
|
|
33
|
+
import { IamClient, createIamAuthMiddleware } from '@easecation/iam-client';
|
|
34
|
+
|
|
35
|
+
const client = new IamClient({
|
|
36
|
+
iamBaseUrl: 'http://localhost:8401',
|
|
37
|
+
clientId: '10007',
|
|
38
|
+
clientSecret: 'YOUR_CLIENT_SECRET',
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const iamAuth = createIamAuthMiddleware(client);
|
|
42
|
+
|
|
43
|
+
const router = express.Router();
|
|
44
|
+
router.get('/profile', iamAuth(), (req, res) => {
|
|
45
|
+
const iamReq = req as any;
|
|
46
|
+
res.json({ uid: iamReq.iamUid, permissions: iamReq.iamPermissions });
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
router.post('/admin', iamAuth(['admin.write']), handler);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## API Highlights
|
|
53
|
+
|
|
54
|
+
- `getAppSessionToken()`
|
|
55
|
+
- `exchangeOAuthCode(code, redirectUri)`
|
|
56
|
+
- `verifyToken(accessToken)`
|
|
57
|
+
- `refreshToken(refreshToken)`
|
|
58
|
+
- `revokeToken(refreshToken)`
|
|
59
|
+
- `getUserProfile(accessToken)`
|
|
60
|
+
- `getUserPermissions(userId, targetApplicationId?)`
|
|
61
|
+
- `getJwks()`
|
|
62
|
+
|
|
63
|
+
## Notes
|
|
64
|
+
|
|
65
|
+
- App session authentication uses the `X-App-Session-Token` header.
|
|
66
|
+
- Verify results are cached locally with a TTL that never exceeds the access token expiration.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IamClient — IAM V2 API wrapper.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* const client = new IamClient({
|
|
6
|
+
* iamBaseUrl: 'http://authapi.easecation.net',
|
|
7
|
+
* clientId: '10007',
|
|
8
|
+
* clientSecret: 'secret',
|
|
9
|
+
* });
|
|
10
|
+
*
|
|
11
|
+
* // Exchange OAuth code during login callback
|
|
12
|
+
* const tokens = await client.exchangeOAuthCode(code, redirectUri);
|
|
13
|
+
*
|
|
14
|
+
* // Verify a token on each request
|
|
15
|
+
* const result = await client.verifyToken(accessToken);
|
|
16
|
+
*/
|
|
17
|
+
import { IamClientConfig, OAuthTokenData, VerifyTokenData, RefreshTokenData, JwksData, UserProfileData } from './types';
|
|
18
|
+
export declare class IamClient {
|
|
19
|
+
private readonly config;
|
|
20
|
+
private readonly http;
|
|
21
|
+
/** Cached app session token */
|
|
22
|
+
private cachedAppToken;
|
|
23
|
+
/** Permission/verify cache keyed by access_token */
|
|
24
|
+
private verifyCache;
|
|
25
|
+
constructor(config: IamClientConfig);
|
|
26
|
+
/**
|
|
27
|
+
* Get (or return cached) the App Session Token.
|
|
28
|
+
* This token is used to authenticate subsequent API calls to IAM.
|
|
29
|
+
*/
|
|
30
|
+
getAppSessionToken(): Promise<string>;
|
|
31
|
+
/** Invalidate the cached app session token (force re-auth on next call). */
|
|
32
|
+
invalidateAppToken(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Exchange an OAuth2 authorization code for a V2 token pair.
|
|
35
|
+
* Returns { access_token, expires_in, refresh_token, refresh_token_expires_in }.
|
|
36
|
+
*/
|
|
37
|
+
exchangeOAuthCode(code: string, redirectUri: string): Promise<OAuthTokenData>;
|
|
38
|
+
/**
|
|
39
|
+
* Verify an Access Token and retrieve the associated permissions.
|
|
40
|
+
* Results are cached for `permissionCacheTtlMs` to avoid hammering IAM.
|
|
41
|
+
*/
|
|
42
|
+
verifyToken(accessToken: string): Promise<VerifyTokenData>;
|
|
43
|
+
/** Remove a token from the local verify cache (e.g. after logout). */
|
|
44
|
+
evictFromVerifyCache(accessToken: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Exchange a Refresh Token for a new Access Token.
|
|
47
|
+
*/
|
|
48
|
+
refreshToken(refreshToken: string): Promise<RefreshTokenData>;
|
|
49
|
+
/**
|
|
50
|
+
* Revoke a session by its Refresh Token (logout).
|
|
51
|
+
*/
|
|
52
|
+
revokeToken(refreshToken: string): Promise<boolean>;
|
|
53
|
+
/**
|
|
54
|
+
* Fetch the JWKS (JSON Web Key Set) from IAM.
|
|
55
|
+
* Used for local RS256 token verification without a network call.
|
|
56
|
+
*/
|
|
57
|
+
getJwks(): Promise<JwksData>;
|
|
58
|
+
/**
|
|
59
|
+
* Get profile of the user who owns the given Access Token.
|
|
60
|
+
*/
|
|
61
|
+
getUserProfile(accessToken: string): Promise<UserProfileData>;
|
|
62
|
+
/**
|
|
63
|
+
* Get permissions for a specific user+application.
|
|
64
|
+
* @param userId IAM uid
|
|
65
|
+
* @param targetApplicationId Defaults to the calling application.
|
|
66
|
+
*/
|
|
67
|
+
getUserPermissions(userId: number, targetApplicationId?: number): Promise<string[]>;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=IamClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IamClient.d.ts","sourceRoot":"","sources":["../src/IamClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EACL,eAAe,EAGf,cAAc,EACd,eAAe,EACf,gBAAgB,EAEhB,QAAQ,EACR,eAAe,EAEhB,MAAM,SAAS,CAAC;AAYjB,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IACnD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IAErC,+BAA+B;IAC/B,OAAO,CAAC,cAAc,CAA+B;IAErD,oDAAoD;IACpD,OAAO,CAAC,WAAW,CAAyC;gBAEhD,MAAM,EAAE,eAAe;IAiBnC;;;OAGG;IACG,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC;IA2B3C,4EAA4E;IAC5E,kBAAkB,IAAI,IAAI;IAM1B;;;OAGG;IACG,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAmBnF;;;OAGG;IACG,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAoChE,sEAAsE;IACtE,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAM/C;;OAEG;IACG,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAmBnE;;OAEG;IACG,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAezD;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC;IAOlC;;OAEG;IACG,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAmBnE;;;;OAIG;IACG,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,mBAAmB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAqB1F"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* IamClient — IAM V2 API wrapper.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* const client = new IamClient({
|
|
7
|
+
* iamBaseUrl: 'http://authapi.easecation.net',
|
|
8
|
+
* clientId: '10007',
|
|
9
|
+
* clientSecret: 'secret',
|
|
10
|
+
* });
|
|
11
|
+
*
|
|
12
|
+
* // Exchange OAuth code during login callback
|
|
13
|
+
* const tokens = await client.exchangeOAuthCode(code, redirectUri);
|
|
14
|
+
*
|
|
15
|
+
* // Verify a token on each request
|
|
16
|
+
* const result = await client.verifyToken(accessToken);
|
|
17
|
+
*/
|
|
18
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
19
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
20
|
+
};
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.IamClient = void 0;
|
|
23
|
+
const axios_1 = __importDefault(require("axios"));
|
|
24
|
+
class IamClient {
|
|
25
|
+
constructor(config) {
|
|
26
|
+
/** Cached app session token */
|
|
27
|
+
this.cachedAppToken = null;
|
|
28
|
+
/** Permission/verify cache keyed by access_token */
|
|
29
|
+
this.verifyCache = new Map();
|
|
30
|
+
this.config = {
|
|
31
|
+
appTokenCacheTtlMs: 55 * 60 * 1000, // 55 minutes
|
|
32
|
+
permissionCacheTtlMs: 5 * 60 * 1000, // 5 minutes
|
|
33
|
+
timeoutMs: 5000,
|
|
34
|
+
...config,
|
|
35
|
+
};
|
|
36
|
+
this.http = axios_1.default.create({
|
|
37
|
+
baseURL: this.config.iamBaseUrl,
|
|
38
|
+
timeout: this.config.timeoutMs,
|
|
39
|
+
headers: { 'Content-Type': 'application/json' },
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
// ── App Session Token ────────────────────────────────────────────────────────
|
|
43
|
+
/**
|
|
44
|
+
* Get (or return cached) the App Session Token.
|
|
45
|
+
* This token is used to authenticate subsequent API calls to IAM.
|
|
46
|
+
*/
|
|
47
|
+
async getAppSessionToken() {
|
|
48
|
+
const now = Date.now();
|
|
49
|
+
if (this.cachedAppToken && now < this.cachedAppToken.expiresAt) {
|
|
50
|
+
return this.cachedAppToken.token;
|
|
51
|
+
}
|
|
52
|
+
const response = await this.http.post('/api/open/v2/token', {
|
|
53
|
+
client_id: this.config.clientId,
|
|
54
|
+
client_secret: this.config.clientSecret,
|
|
55
|
+
});
|
|
56
|
+
const data = response.data;
|
|
57
|
+
if (!data.success || !data.data?.applicationSessionToken) {
|
|
58
|
+
throw new Error(`IAM: Failed to get app token: ${data.message || data.code}`);
|
|
59
|
+
}
|
|
60
|
+
this.cachedAppToken = {
|
|
61
|
+
token: data.data.applicationSessionToken,
|
|
62
|
+
expiresAt: now + this.config.appTokenCacheTtlMs,
|
|
63
|
+
};
|
|
64
|
+
return this.cachedAppToken.token;
|
|
65
|
+
}
|
|
66
|
+
/** Invalidate the cached app session token (force re-auth on next call). */
|
|
67
|
+
invalidateAppToken() {
|
|
68
|
+
this.cachedAppToken = null;
|
|
69
|
+
}
|
|
70
|
+
// ── OAuth2 Code Exchange ─────────────────────────────────────────────────────
|
|
71
|
+
/**
|
|
72
|
+
* Exchange an OAuth2 authorization code for a V2 token pair.
|
|
73
|
+
* Returns { access_token, expires_in, refresh_token, refresh_token_expires_in }.
|
|
74
|
+
*/
|
|
75
|
+
async exchangeOAuthCode(code, redirectUri) {
|
|
76
|
+
const appToken = await this.getAppSessionToken();
|
|
77
|
+
const response = await this.http.post('/api/open/v2/oauth/token', { code, redirect_uri: redirectUri }, { headers: { 'X-App-Session-Token': appToken } });
|
|
78
|
+
const data = response.data;
|
|
79
|
+
if (!data.success || !data.data) {
|
|
80
|
+
throw new Error(`IAM: OAuth code exchange failed: ${data.message || data.code}`);
|
|
81
|
+
}
|
|
82
|
+
return data.data;
|
|
83
|
+
}
|
|
84
|
+
// ── Token Verify ─────────────────────────────────────────────────────────────
|
|
85
|
+
/**
|
|
86
|
+
* Verify an Access Token and retrieve the associated permissions.
|
|
87
|
+
* Results are cached for `permissionCacheTtlMs` to avoid hammering IAM.
|
|
88
|
+
*/
|
|
89
|
+
async verifyToken(accessToken) {
|
|
90
|
+
const now = Date.now();
|
|
91
|
+
const cached = this.verifyCache.get(accessToken);
|
|
92
|
+
if (cached && now < cached.expiresAt) {
|
|
93
|
+
return cached.result;
|
|
94
|
+
}
|
|
95
|
+
const appToken = await this.getAppSessionToken();
|
|
96
|
+
const response = await this.http.post('/api/open/v2/verify', { access_token: accessToken }, { headers: { 'X-App-Session-Token': appToken } });
|
|
97
|
+
const data = response.data;
|
|
98
|
+
if (!data.success || !data.data) {
|
|
99
|
+
// Evict any stale cache entry so the next request also hits IAM
|
|
100
|
+
// (covers the case where IAM revoked the session between cache fills)
|
|
101
|
+
this.verifyCache.delete(accessToken);
|
|
102
|
+
throw new Error(`IAM: Token verification failed: ${data.message || data.code}`);
|
|
103
|
+
}
|
|
104
|
+
// Cache should never outlive the access token expiration.
|
|
105
|
+
const expMs = data.data.exp * 1000;
|
|
106
|
+
const cacheExpiresAt = Math.min(now + this.config.permissionCacheTtlMs, expMs - 1000);
|
|
107
|
+
if (cacheExpiresAt > now) {
|
|
108
|
+
this.verifyCache.set(accessToken, {
|
|
109
|
+
result: data.data,
|
|
110
|
+
expiresAt: cacheExpiresAt,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
return data.data;
|
|
114
|
+
}
|
|
115
|
+
/** Remove a token from the local verify cache (e.g. after logout). */
|
|
116
|
+
evictFromVerifyCache(accessToken) {
|
|
117
|
+
this.verifyCache.delete(accessToken);
|
|
118
|
+
}
|
|
119
|
+
// ── Token Refresh ─────────────────────────────────────────────────────────────
|
|
120
|
+
/**
|
|
121
|
+
* Exchange a Refresh Token for a new Access Token.
|
|
122
|
+
*/
|
|
123
|
+
async refreshToken(refreshToken) {
|
|
124
|
+
const appToken = await this.getAppSessionToken();
|
|
125
|
+
const response = await this.http.post('/api/open/v2/refresh', { refresh_token: refreshToken }, { headers: { 'X-App-Session-Token': appToken } });
|
|
126
|
+
const data = response.data;
|
|
127
|
+
if (!data.success || !data.data) {
|
|
128
|
+
throw new Error(`IAM: Token refresh failed: ${data.message || data.code}`);
|
|
129
|
+
}
|
|
130
|
+
return data.data;
|
|
131
|
+
}
|
|
132
|
+
// ── Session Revoke ────────────────────────────────────────────────────────────
|
|
133
|
+
/**
|
|
134
|
+
* Revoke a session by its Refresh Token (logout).
|
|
135
|
+
*/
|
|
136
|
+
async revokeToken(refreshToken) {
|
|
137
|
+
const appToken = await this.getAppSessionToken();
|
|
138
|
+
const response = await this.http.post('/api/open/v2/revoke', { refresh_token: refreshToken }, { headers: { 'X-App-Session-Token': appToken } });
|
|
139
|
+
const data = response.data;
|
|
140
|
+
return !!(data.success && data.data?.revoked);
|
|
141
|
+
}
|
|
142
|
+
// ── JWKS ──────────────────────────────────────────────────────────────────────
|
|
143
|
+
/**
|
|
144
|
+
* Fetch the JWKS (JSON Web Key Set) from IAM.
|
|
145
|
+
* Used for local RS256 token verification without a network call.
|
|
146
|
+
*/
|
|
147
|
+
async getJwks() {
|
|
148
|
+
const response = await this.http.get('/api/open/v2/jwks');
|
|
149
|
+
return response.data;
|
|
150
|
+
}
|
|
151
|
+
// ── User Profile ──────────────────────────────────────────────────────────────
|
|
152
|
+
/**
|
|
153
|
+
* Get profile of the user who owns the given Access Token.
|
|
154
|
+
*/
|
|
155
|
+
async getUserProfile(accessToken) {
|
|
156
|
+
const appToken = await this.getAppSessionToken();
|
|
157
|
+
const response = await this.http.post('/api/open/v2/user/profile', { access_token: accessToken }, { headers: { 'X-App-Session-Token': appToken } });
|
|
158
|
+
const data = response.data;
|
|
159
|
+
if (!data.success || !data.data) {
|
|
160
|
+
throw new Error(`IAM: getUserProfile failed: ${data.message || data.code}`);
|
|
161
|
+
}
|
|
162
|
+
return data.data;
|
|
163
|
+
}
|
|
164
|
+
// ── User Permissions ──────────────────────────────────────────────────────────
|
|
165
|
+
/**
|
|
166
|
+
* Get permissions for a specific user+application.
|
|
167
|
+
* @param userId IAM uid
|
|
168
|
+
* @param targetApplicationId Defaults to the calling application.
|
|
169
|
+
*/
|
|
170
|
+
async getUserPermissions(userId, targetApplicationId) {
|
|
171
|
+
const appToken = await this.getAppSessionToken();
|
|
172
|
+
const body = { user_id: userId };
|
|
173
|
+
if (targetApplicationId !== undefined) {
|
|
174
|
+
body.target_application_id = targetApplicationId;
|
|
175
|
+
}
|
|
176
|
+
const response = await this.http.post('/api/open/v2/user/permissions', body, { headers: { 'X-App-Session-Token': appToken } });
|
|
177
|
+
const data = response.data;
|
|
178
|
+
if (!data.success || !data.data) {
|
|
179
|
+
throw new Error(`IAM: getUserPermissions failed: ${data.message || data.code}`);
|
|
180
|
+
}
|
|
181
|
+
return data.data.permissions;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
exports.IamClient = IamClient;
|
|
185
|
+
//# sourceMappingURL=IamClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IamClient.js","sourceRoot":"","sources":["../src/IamClient.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { IamClient } from './IamClient';
|
|
2
|
+
export { createIamAuthMiddleware } from './middleware';
|
|
3
|
+
export type { IamRequest } from './middleware';
|
|
4
|
+
export type { IamClientConfig, IamApiResponse, AppTokenData, OAuthTokenData, VerifyTokenData, RefreshTokenData, RevokeTokenData, JwkData, JwksData, UserProfileData, UserPermissionsData, DecodedAccessToken, IamAuthRequest, } from './types';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,YAAY,EACV,eAAe,EACf,cAAc,EACd,YAAY,EACZ,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,OAAO,EACP,QAAQ,EACR,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,GACf,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createIamAuthMiddleware = exports.IamClient = void 0;
|
|
4
|
+
var IamClient_1 = require("./IamClient");
|
|
5
|
+
Object.defineProperty(exports, "IamClient", { enumerable: true, get: function () { return IamClient_1.IamClient; } });
|
|
6
|
+
var middleware_1 = require("./middleware");
|
|
7
|
+
Object.defineProperty(exports, "createIamAuthMiddleware", { enumerable: true, get: function () { return middleware_1.createIamAuthMiddleware; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,yCAAwC;AAA/B,sGAAA,SAAS,OAAA;AAClB,2CAAuD;AAA9C,qHAAA,uBAAuB,OAAA"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Express middleware factory for IAM V2 authentication.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import { createIamAuthMiddleware } from '@easecation/iam-client';
|
|
6
|
+
*
|
|
7
|
+
* const iamAuth = createIamAuthMiddleware(iamClient);
|
|
8
|
+
*
|
|
9
|
+
* // Protect a route (no permission requirements)
|
|
10
|
+
* router.get('/profile', iamAuth(), handler);
|
|
11
|
+
*
|
|
12
|
+
* // Protect a route and require specific permissions
|
|
13
|
+
* router.post('/admin', iamAuth(['admin.write']), handler);
|
|
14
|
+
*/
|
|
15
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
16
|
+
import { IamClient } from './IamClient';
|
|
17
|
+
/** Express Request extended with IAM claims */
|
|
18
|
+
export interface IamRequest extends Request {
|
|
19
|
+
iamUid: number;
|
|
20
|
+
iamApplicationId: number;
|
|
21
|
+
iamPermissions: string[];
|
|
22
|
+
iamTokenExp: number;
|
|
23
|
+
}
|
|
24
|
+
type IamMiddlewareFn = (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Create an auth middleware factory bound to an IamClient instance.
|
|
27
|
+
*
|
|
28
|
+
* @param client Configured IamClient.
|
|
29
|
+
* @returns A function `iamAuth(requiredPermissions?)` that returns an Express middleware.
|
|
30
|
+
*/
|
|
31
|
+
export declare function createIamAuthMiddleware(client: IamClient): (requiredPermissions?: string[]) => IamMiddlewareFn;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,+CAA+C;AAC/C,MAAM,WAAW,UAAW,SAAQ,OAAO;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,KAAK,eAAe,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1F;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,IAC/B,sBAAqB,MAAM,EAAO,KAAG,eAAe,CAwE7E"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Express middleware factory for IAM V2 authentication.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* import { createIamAuthMiddleware } from '@easecation/iam-client';
|
|
7
|
+
*
|
|
8
|
+
* const iamAuth = createIamAuthMiddleware(iamClient);
|
|
9
|
+
*
|
|
10
|
+
* // Protect a route (no permission requirements)
|
|
11
|
+
* router.get('/profile', iamAuth(), handler);
|
|
12
|
+
*
|
|
13
|
+
* // Protect a route and require specific permissions
|
|
14
|
+
* router.post('/admin', iamAuth(['admin.write']), handler);
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.createIamAuthMiddleware = createIamAuthMiddleware;
|
|
18
|
+
/**
|
|
19
|
+
* Create an auth middleware factory bound to an IamClient instance.
|
|
20
|
+
*
|
|
21
|
+
* @param client Configured IamClient.
|
|
22
|
+
* @returns A function `iamAuth(requiredPermissions?)` that returns an Express middleware.
|
|
23
|
+
*/
|
|
24
|
+
function createIamAuthMiddleware(client) {
|
|
25
|
+
return function iamAuth(requiredPermissions = []) {
|
|
26
|
+
return async (req, res, next) => {
|
|
27
|
+
const authHeader = req.headers['authorization'];
|
|
28
|
+
if (!authHeader) {
|
|
29
|
+
res.status(401).json({ success: false, message: 'Missing authorization header' });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const parts = authHeader.split(' ');
|
|
33
|
+
if (parts.length !== 2 || parts[0] !== 'Bearer') {
|
|
34
|
+
res.status(401).json({ success: false, message: 'Invalid authorization format' });
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const accessToken = parts[1];
|
|
38
|
+
try {
|
|
39
|
+
const result = await client.verifyToken(accessToken);
|
|
40
|
+
if (!result.valid) {
|
|
41
|
+
res.status(401).json({ success: false, message: 'Invalid access token' });
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// Permission check
|
|
45
|
+
if (requiredPermissions.length > 0) {
|
|
46
|
+
const hasAll = requiredPermissions.every(p => result.permissions.includes(p));
|
|
47
|
+
if (!hasAll) {
|
|
48
|
+
res.status(403).json({ success: false, message: 'Insufficient permissions' });
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Attach claims to request
|
|
53
|
+
const iamReq = req;
|
|
54
|
+
iamReq.iamUid = result.uid;
|
|
55
|
+
iamReq.iamApplicationId = result.application_id;
|
|
56
|
+
iamReq.iamPermissions = result.permissions;
|
|
57
|
+
iamReq.iamTokenExp = result.exp;
|
|
58
|
+
next();
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
// Distinguish IAM-reported token errors from network / server errors.
|
|
62
|
+
// IamClient.verifyToken throws "IAM: Token verification failed: <CODE>"
|
|
63
|
+
// for token-level rejections. Network errors carry an error.code.
|
|
64
|
+
const msg = error?.message || '';
|
|
65
|
+
const isTokenError = msg.startsWith('IAM: Token verification failed:') ||
|
|
66
|
+
msg === 'IAM: Token verification failed: ERROR_V2_INVALID_TOKEN' ||
|
|
67
|
+
msg === 'IAM: Token verification failed: ERROR_V2_TOKEN_EXPIRED';
|
|
68
|
+
const isNetworkError = error?.code === 'ECONNREFUSED' ||
|
|
69
|
+
error?.code === 'ENOTFOUND' ||
|
|
70
|
+
error?.code === 'ETIMEDOUT' ||
|
|
71
|
+
(error?.response?.status != null && error.response.status >= 500);
|
|
72
|
+
if (isTokenError) {
|
|
73
|
+
res.status(401).json({ success: false, message: 'Invalid or expired access token' });
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (isNetworkError) {
|
|
77
|
+
console.error('[IamClient] IAM unreachable:', error?.code || error?.message);
|
|
78
|
+
res.status(503).json({ success: false, message: 'Authentication service temporarily unavailable' });
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
console.error('[IamClient] Auth middleware error:', error);
|
|
82
|
+
res.status(500).json({ success: false, message: 'Authentication service error' });
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the @easecation/iam-client package.
|
|
3
|
+
*/
|
|
4
|
+
export interface IamApiResponse<T = unknown> {
|
|
5
|
+
success: boolean;
|
|
6
|
+
data?: T;
|
|
7
|
+
message?: string;
|
|
8
|
+
code?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface AppTokenData {
|
|
11
|
+
applicationSessionToken: string;
|
|
12
|
+
applicationId: number;
|
|
13
|
+
}
|
|
14
|
+
export interface OAuthTokenData {
|
|
15
|
+
access_token: string;
|
|
16
|
+
expires_in: number;
|
|
17
|
+
refresh_token: string;
|
|
18
|
+
refresh_token_expires_in: number;
|
|
19
|
+
token_type: 'Bearer';
|
|
20
|
+
}
|
|
21
|
+
export interface VerifyTokenData {
|
|
22
|
+
valid: boolean;
|
|
23
|
+
uid: number;
|
|
24
|
+
application_id: number;
|
|
25
|
+
permissions: string[];
|
|
26
|
+
exp: number;
|
|
27
|
+
}
|
|
28
|
+
export interface RefreshTokenData {
|
|
29
|
+
access_token: string;
|
|
30
|
+
expires_in: number;
|
|
31
|
+
token_type: 'Bearer';
|
|
32
|
+
}
|
|
33
|
+
export interface RevokeTokenData {
|
|
34
|
+
revoked: boolean;
|
|
35
|
+
}
|
|
36
|
+
export interface JwkData {
|
|
37
|
+
kty: 'RSA';
|
|
38
|
+
use: 'sig';
|
|
39
|
+
alg: 'RS256';
|
|
40
|
+
kid: string;
|
|
41
|
+
n: string;
|
|
42
|
+
e: string;
|
|
43
|
+
}
|
|
44
|
+
export interface JwksData {
|
|
45
|
+
keys: JwkData[];
|
|
46
|
+
}
|
|
47
|
+
export interface UserProfileData {
|
|
48
|
+
uid: number;
|
|
49
|
+
name: string;
|
|
50
|
+
email: string;
|
|
51
|
+
status: string;
|
|
52
|
+
}
|
|
53
|
+
export interface UserPermissionsData {
|
|
54
|
+
permissions: string[];
|
|
55
|
+
application_id: number;
|
|
56
|
+
user_id: number;
|
|
57
|
+
}
|
|
58
|
+
export interface IamClientConfig {
|
|
59
|
+
/** IAM backend URL, e.g. http://authapi.easecation.net */
|
|
60
|
+
iamBaseUrl: string;
|
|
61
|
+
/** Application client_id */
|
|
62
|
+
clientId: string;
|
|
63
|
+
/** Application client_secret */
|
|
64
|
+
clientSecret: string;
|
|
65
|
+
/**
|
|
66
|
+
* How long (ms) to cache the App Session Token.
|
|
67
|
+
* Defaults to 55 minutes (token lifetime is 1h by default in V1).
|
|
68
|
+
*/
|
|
69
|
+
appTokenCacheTtlMs?: number;
|
|
70
|
+
/**
|
|
71
|
+
* How long (ms) to cache permission verification results locally.
|
|
72
|
+
* Defaults to 5 minutes.
|
|
73
|
+
*/
|
|
74
|
+
permissionCacheTtlMs?: number;
|
|
75
|
+
/**
|
|
76
|
+
* Request timeout (ms). Defaults to 5000.
|
|
77
|
+
*/
|
|
78
|
+
timeoutMs?: number;
|
|
79
|
+
}
|
|
80
|
+
export interface DecodedAccessToken {
|
|
81
|
+
uid: number;
|
|
82
|
+
app: number;
|
|
83
|
+
jti: string;
|
|
84
|
+
iat: number;
|
|
85
|
+
exp: number;
|
|
86
|
+
iss: string;
|
|
87
|
+
}
|
|
88
|
+
/** Augment Express Request with IAM claims */
|
|
89
|
+
export interface IamAuthRequest {
|
|
90
|
+
iamUid: number;
|
|
91
|
+
iamApplicationId: number;
|
|
92
|
+
iamPermissions: string[];
|
|
93
|
+
iamTokenExp: number;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,cAAc,CAAC,CAAC,GAAG,OAAO;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,uBAAuB,EAAE,MAAM,CAAC;IAChC,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,wBAAwB,EAAE,MAAM,CAAC;IACjC,UAAU,EAAE,QAAQ,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,QAAQ,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,KAAK,CAAC;IACX,GAAG,EAAE,KAAK,CAAC;IACX,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,OAAO,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAID,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC;IACnB,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAID,8CAA8C;AAC9C,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;GAEG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@easecation/iam-client",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "IAM V2 client library for EaseCation services",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"require": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"iam",
|
|
23
|
+
"oauth",
|
|
24
|
+
"jwt",
|
|
25
|
+
"rbac",
|
|
26
|
+
"easecation"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc",
|
|
30
|
+
"dev": "tsc --watch"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"axios": "^1.6.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/express": "^4.17.21",
|
|
37
|
+
"@types/node": "^20.0.0",
|
|
38
|
+
"typescript": "^5.0.0"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"express": ">=4.0.0"
|
|
42
|
+
},
|
|
43
|
+
"peerDependenciesMeta": {
|
|
44
|
+
"express": {
|
|
45
|
+
"optional": true
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|