@eetr/eetr-auth-client 0.3.1 → 0.5.2
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 +350 -0
- package/dist/admin.d.ts +82 -0
- package/dist/admin.d.ts.map +1 -1
- package/dist/admin.js +96 -0
- package/dist/admin.js.map +1 -1
- package/dist/api.d.ts +130 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +120 -4
- package/dist/api.js.map +1 -1
- package/dist/index.d.ts +10 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/jwt.d.ts +11 -1
- package/dist/jwt.d.ts.map +1 -1
- package/dist/jwt.js +13 -0
- package/dist/jwt.js.map +1 -1
- package/dist/profile.d.ts +14 -0
- package/dist/profile.d.ts.map +1 -0
- package/dist/profile.js +23 -0
- package/dist/profile.js.map +1 -0
- package/dist/scopes.d.ts +25 -0
- package/dist/scopes.d.ts.map +1 -0
- package/dist/scopes.js +43 -0
- package/dist/scopes.js.map +1 -0
- package/dist/types.d.ts +43 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +32 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 eetr-ai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
# @eetr/eetr-auth-client
|
|
2
|
+
|
|
3
|
+
TypeScript client library for the [eetr-auth](https://github.com/eetr-ai/eetr-auth) OAuth 2.1 / OIDC server.
|
|
4
|
+
|
|
5
|
+
It wraps the server's token, introspection, UserInfo, admin, and passkey-management
|
|
6
|
+
endpoints, plus helpers for OIDC discovery and JWT verification. Everything is
|
|
7
|
+
`fetch`-based and ships with full type definitions.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @eetr/eetr-auth-client
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add @eetr/eetr-auth-client
|
|
17
|
+
# or
|
|
18
|
+
yarn add @eetr/eetr-auth-client
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Requirements:** Node.js 18+ (the library relies on the global `fetch`; `decodeJwtPayload`
|
|
22
|
+
also uses Node's `Buffer`). `jose` is a runtime dependency used for JWT verification.
|
|
23
|
+
|
|
24
|
+
The package is ESM-only (`"type": "module"`) and exports both JavaScript and `.d.ts` types.
|
|
25
|
+
|
|
26
|
+
## Quick start
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import {
|
|
30
|
+
fetchOIDCDiscovery,
|
|
31
|
+
exchangeToken,
|
|
32
|
+
validateJwt,
|
|
33
|
+
getUserInfo,
|
|
34
|
+
} from "@eetr/eetr-auth-client";
|
|
35
|
+
|
|
36
|
+
const ISSUER = "https://auth.example.com";
|
|
37
|
+
|
|
38
|
+
// 1. Discover endpoints
|
|
39
|
+
const discovery = await fetchOIDCDiscovery(ISSUER);
|
|
40
|
+
|
|
41
|
+
// 2. Exchange an authorization code for tokens (PKCE)
|
|
42
|
+
const tokens = await exchangeToken(
|
|
43
|
+
{
|
|
44
|
+
grantType: "authorization_code",
|
|
45
|
+
clientId: "my-client",
|
|
46
|
+
code: authorizationCode,
|
|
47
|
+
redirectUri: "https://app.example.com/callback",
|
|
48
|
+
codeVerifier,
|
|
49
|
+
},
|
|
50
|
+
{ tokenEndpoint: discovery.token_endpoint }
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
// 3. Verify the access/ID token against the server's JWKS
|
|
54
|
+
const payload = await validateJwt(tokens.access_token, discovery.jwks_uri, {
|
|
55
|
+
issuer: ISSUER,
|
|
56
|
+
audience: "my-client",
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// 4. Fetch the user's profile
|
|
60
|
+
const user = await getUserInfo(tokens.access_token, discovery.userinfo_endpoint);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## API reference
|
|
64
|
+
|
|
65
|
+
### Discovery
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
fetchOIDCDiscovery(issuerUrl: string): Promise<OIDCDiscovery>
|
|
69
|
+
fetchOAuthMetadata(issuerUrl: string): Promise<OAuthServerMetadata>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Fetch the server's `/.well-known/openid-configuration` or
|
|
73
|
+
`/.well-known/oauth-authorization-server` metadata. Use the returned
|
|
74
|
+
`token_endpoint`, `jwks_uri`, `userinfo_endpoint`, etc. to configure the rest of
|
|
75
|
+
the client rather than hard-coding paths.
|
|
76
|
+
|
|
77
|
+
### Authorization URL
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
buildAuthorizationUrl(authorizationEndpoint: string, params: AuthorizationUrlParams): string
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Builds the authorization-request URL for the `authorization_code` + PKCE flow.
|
|
84
|
+
`code_challenge` is required (the server only accepts `S256`). Pass `nonce` to
|
|
85
|
+
request an OIDC `nonce` that the server binds into the issued `id_token`, then
|
|
86
|
+
verify it on the returned token with [`validateIdToken`](#jwt-verification).
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
const url = buildAuthorizationUrl(discovery.authorization_endpoint, {
|
|
90
|
+
clientId: "my-client",
|
|
91
|
+
redirectUri: "https://app.example.com/callback",
|
|
92
|
+
codeChallenge, // base64url SHA-256 of your PKCE verifier
|
|
93
|
+
scope: "openid profile email",
|
|
94
|
+
state,
|
|
95
|
+
nonce,
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Prefer the `OIDCScope` constants and the `scopes` array so a typo can't silently
|
|
100
|
+
drop `openid` (which would make `/userinfo` return `403 insufficient_scope`). `scope`
|
|
101
|
+
and `scopes` are merged and de-duplicated, so either or both work:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
import { OIDCScope, STANDARD_OIDC_SCOPES } from "@eetr/eetr-auth-client";
|
|
105
|
+
|
|
106
|
+
const url = buildAuthorizationUrl(discovery.authorization_endpoint, {
|
|
107
|
+
clientId: "my-client",
|
|
108
|
+
redirectUri: "https://app.example.com/callback",
|
|
109
|
+
codeChallenge,
|
|
110
|
+
scopes: [OIDCScope.OpenId, OIDCScope.Profile, OIDCScope.Email], // or STANDARD_OIDC_SCOPES
|
|
111
|
+
state,
|
|
112
|
+
nonce,
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
> The client must be **granted** these scopes by an admin, and `openid`/`profile`/`email`
|
|
117
|
+
> are seeded on the server. Requesting a scope the client wasn't granted fails with
|
|
118
|
+
> `invalid_scope`.
|
|
119
|
+
|
|
120
|
+
### Token exchange
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
exchangeToken(params: ExchangeTokenParams, config: ExchangeTokenConfig): Promise<TokenResponse>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Performs an OAuth token request. `grantType` is one of `"authorization_code"`,
|
|
127
|
+
`"client_credentials"`, or `"refresh_token"`; supply the fields relevant to the grant.
|
|
128
|
+
When the `openid` scope was granted on an `authorization_code` exchange, the
|
|
129
|
+
`TokenResponse` also includes a signed `id_token`.
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
// Client credentials (machine-to-machine)
|
|
133
|
+
const tokens = await exchangeToken(
|
|
134
|
+
{
|
|
135
|
+
grantType: "client_credentials",
|
|
136
|
+
clientId: "service-a",
|
|
137
|
+
clientSecret: process.env.CLIENT_SECRET,
|
|
138
|
+
scope: "admin",
|
|
139
|
+
},
|
|
140
|
+
{ tokenEndpoint: discovery.token_endpoint }
|
|
141
|
+
);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
On a non-2xx response it throws an [`OAuthError`](#error-handling) carrying the
|
|
145
|
+
server's `error` code and `error_description`.
|
|
146
|
+
|
|
147
|
+
### TokenManager
|
|
148
|
+
|
|
149
|
+
A small helper that caches an access token and transparently refreshes it (using a
|
|
150
|
+
30-second expiry skew) when a refresh token is available.
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import { TokenManager } from "@eetr/eetr-auth-client";
|
|
154
|
+
|
|
155
|
+
const manager = new TokenManager({
|
|
156
|
+
issuerUrl: ISSUER,
|
|
157
|
+
clientId: "my-client",
|
|
158
|
+
clientSecret: process.env.CLIENT_SECRET, // optional for public clients
|
|
159
|
+
tokenEndpoint: discovery.token_endpoint,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
manager.setTokens(tokens); // seed from an initial exchange
|
|
163
|
+
const accessToken = await manager.getAccessToken(); // refreshes if expired
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`getAccessToken()` throws an `OAuthError` with code `no_token` if there is no valid
|
|
167
|
+
token and no refresh token to fall back on.
|
|
168
|
+
|
|
169
|
+
### JWT verification
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
validateJwt(token: string, jwksUri: string, options?: ValidateJwtOptions): Promise<JWTPayload>
|
|
173
|
+
validateIdToken(token: string, jwksUri: string, options?: ValidateIdTokenOptions): Promise<IDTokenClaims>
|
|
174
|
+
decodeJwtPayload(token: string): JWTPayload
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
`validateJwt` verifies the signature against the server's JWKS (remote keys are
|
|
178
|
+
cached per `jwksUri`) and validates `issuer`/`audience`/expiry (`clockTolerance`
|
|
179
|
+
defaults to 5 seconds). `decodeJwtPayload` decodes the payload **without** verifying
|
|
180
|
+
the signature — use it only for inspecting claims you have already verified.
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
const payload = await validateJwt(accessToken, discovery.jwks_uri, {
|
|
184
|
+
issuer: ISSUER,
|
|
185
|
+
audience: "my-client",
|
|
186
|
+
clockTolerance: 10,
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
`validateIdToken` verifies an OIDC `id_token` the same way and, when you pass the
|
|
191
|
+
`nonce` you sent to the authorization endpoint, additionally checks the token's
|
|
192
|
+
`nonce` claim — throwing `id_token nonce mismatch` on a mismatch. It returns the
|
|
193
|
+
typed `IDTokenClaims` (`sub`, `auth_time`, `nonce`, `at_hash`, plus scope-gated
|
|
194
|
+
`name`/`preferred_username`/`picture`/`email`/`email_verified`).
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
const claims = await validateIdToken(tokens.id_token!, discovery.jwks_uri, {
|
|
198
|
+
issuer: ISSUER,
|
|
199
|
+
audience: "my-client",
|
|
200
|
+
nonce, // the value passed to buildAuthorizationUrl
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Token introspection
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
introspectToken(params: IntrospectTokenParams, config: IntrospectTokenConfig): Promise<TokenValidationResponse>
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Asks the server whether a token is active within a given environment. The endpoint
|
|
211
|
+
is published as `token_introspection_endpoint` in the OAuth metadata (defaults to
|
|
212
|
+
`${ISSUER}/api/token/validate`).
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
const metadata = await fetchOAuthMetadata(ISSUER);
|
|
216
|
+
|
|
217
|
+
const result = await introspectToken(
|
|
218
|
+
{ token: accessToken, scopes: ["read"], environmentName: "production" },
|
|
219
|
+
{ introspectionEndpoint: metadata.token_introspection_endpoint! }
|
|
220
|
+
);
|
|
221
|
+
// → { valid, active, client_id, expires_at }
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### UserInfo
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
getUserInfo(accessToken: string, userInfoEndpoint: string): Promise<UserInfoResponse>
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Returns the OIDC UserInfo claims for the bearer token. The endpoint **requires the
|
|
231
|
+
`openid` scope**; only `sub` is always present, and the remaining claims are gated by
|
|
232
|
+
scope (`profile` → `name`/`preferred_username`/`picture`, `email` →
|
|
233
|
+
`email`/`email_verified`).
|
|
234
|
+
|
|
235
|
+
On failure it throws an [`OAuthError`](#error-handling). A token that is valid but
|
|
236
|
+
lacks `openid` yields a `403`, surfaced as `code === "insufficient_scope"` (use
|
|
237
|
+
`err.isInsufficientScope`) so you can re-authorize with the right scopes rather than
|
|
238
|
+
discarding the token:
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
try {
|
|
242
|
+
const info = await getUserInfo(accessToken, discovery.userinfo_endpoint);
|
|
243
|
+
} catch (err) {
|
|
244
|
+
if (err instanceof OAuthError && err.isInsufficientScope) {
|
|
245
|
+
// token is fine but missing `openid` — restart the dance requesting it
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
#### Normalized profile
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
toUserProfile(userInfo: UserInfoResponse, idTokenClaims?: IDTokenClaims): UserProfile
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Merges the UserInfo response (and optionally the decoded `id_token` claims) into a
|
|
257
|
+
single camelCased `UserProfile` (`sub`, `name`, `preferredUsername`, `picture`,
|
|
258
|
+
`email`, `emailVerified`). UserInfo wins; the id_token fills any gap.
|
|
259
|
+
|
|
260
|
+
```ts
|
|
261
|
+
const info = await getUserInfo(tokens.access_token, discovery.userinfo_endpoint);
|
|
262
|
+
const profile = toUserProfile(info, decodeJwtPayload(tokens.id_token!));
|
|
263
|
+
// → { sub, name?, preferredUsername?, picture?, email?, emailVerified? }
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Admin API
|
|
267
|
+
|
|
268
|
+
User management against the server's admin API. Requires an access token from a
|
|
269
|
+
client configured as an **admin API client** on the server.
|
|
270
|
+
|
|
271
|
+
```ts
|
|
272
|
+
import {
|
|
273
|
+
getAdminUser,
|
|
274
|
+
createAdminUser,
|
|
275
|
+
updateAdminUser,
|
|
276
|
+
deleteAdminUser,
|
|
277
|
+
} from "@eetr/eetr-auth-client";
|
|
278
|
+
|
|
279
|
+
const config = { baseUrl: ISSUER, accessToken }; // AdminClientConfig
|
|
280
|
+
|
|
281
|
+
const created = await createAdminUser(
|
|
282
|
+
{ username: "alice", password: "•••", email: "alice@example.com" },
|
|
283
|
+
config
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
await updateAdminUser("alice", { name: "Alice B." }, config);
|
|
287
|
+
const user = await getAdminUser("alice", config); // by username or UUID
|
|
288
|
+
await deleteAdminUser(created.id, config);
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
All admin calls throw `OAuthError` on non-2xx responses.
|
|
292
|
+
|
|
293
|
+
### Passkey management
|
|
294
|
+
|
|
295
|
+
List, rename, and remove a user's passkeys. The access token must belong to the
|
|
296
|
+
user whose passkeys are being managed.
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
import { listPasskeys, renamePasskey, removePasskey } from "@eetr/eetr-auth-client";
|
|
300
|
+
|
|
301
|
+
const config = { baseUrl: ISSUER, accessToken }; // UserClientConfig
|
|
302
|
+
|
|
303
|
+
const passkeys = await listPasskeys(config);
|
|
304
|
+
await renamePasskey(passkeys[0].id, "Work laptop", config);
|
|
305
|
+
await removePasskey(passkeys[0].id, config);
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
> Only passkey *management* is available here. Creating or authenticating with a
|
|
309
|
+
> passkey is a WebAuthn ceremony that requires a browser and cannot be driven from a
|
|
310
|
+
> server-side client. `removePasskey` deletes the server-side record only — it does
|
|
311
|
+
> not remove the credential from the device/authenticator.
|
|
312
|
+
|
|
313
|
+
## Error handling
|
|
314
|
+
|
|
315
|
+
API helpers throw `OAuthError` (a subclass of `Error`) on non-2xx responses, exposing
|
|
316
|
+
the server's machine-readable `code` alongside the message:
|
|
317
|
+
|
|
318
|
+
```ts
|
|
319
|
+
import { OAuthError } from "@eetr/eetr-auth-client";
|
|
320
|
+
|
|
321
|
+
try {
|
|
322
|
+
await exchangeToken(params, config);
|
|
323
|
+
} catch (err) {
|
|
324
|
+
if (err instanceof OAuthError) {
|
|
325
|
+
console.error(err.code, err.message); // e.g. "invalid_grant"
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
`OAuthError` also exposes the HTTP `status` and the server's `description`
|
|
331
|
+
(`error_description`) when available, plus an `isInsufficientScope` convenience for
|
|
332
|
+
the `/userinfo` 403 case (token valid but missing `openid`).
|
|
333
|
+
|
|
334
|
+
The discovery helpers throw a plain `Error` with the HTTP status on failure.
|
|
335
|
+
|
|
336
|
+
## Types
|
|
337
|
+
|
|
338
|
+
The package exports TypeScript types for every request and response shape, including
|
|
339
|
+
`TokenResponse`, `UserInfoResponse`, `UserProfile`, `IDTokenClaims`, `OIDCDiscovery`,
|
|
340
|
+
`OAuthServerMetadata`, `AuthClientConfig`, `JWTPayload`, `TokenValidationResponse`,
|
|
341
|
+
`GrantType`, `ExchangeTokenParams`/`Config`, `AuthorizationUrlParams`,
|
|
342
|
+
`IntrospectTokenParams`/`Config`, `OIDCScopeValue`, `ValidateJwtOptions`,
|
|
343
|
+
`ValidateIdTokenOptions`, `AdminUserRecord`, `AdminClientConfig`, `CreateUserParams`,
|
|
344
|
+
`UpdateUserParams`, `PasskeySummary`, and `UserClientConfig`. It also exports the
|
|
345
|
+
`OIDCScope` / `STANDARD_OIDC_SCOPES` constants, the `resolveScopeParam` helper, and
|
|
346
|
+
the `toUserProfile` profile normalizer.
|
|
347
|
+
|
|
348
|
+
## License
|
|
349
|
+
|
|
350
|
+
See the [eetr-auth repository](https://github.com/eetr-ai/eetr-auth).
|
package/dist/admin.d.ts
CHANGED
|
@@ -18,6 +18,54 @@ export interface CreateUserParams {
|
|
|
18
18
|
name?: string | null;
|
|
19
19
|
email?: string | null;
|
|
20
20
|
}
|
|
21
|
+
export interface AdminConsentRecord {
|
|
22
|
+
/** The client's public client_id. */
|
|
23
|
+
clientId: string;
|
|
24
|
+
clientName: string | null;
|
|
25
|
+
/** The scope names this user has consented to for that client. */
|
|
26
|
+
scopes: string[];
|
|
27
|
+
createdAt: string;
|
|
28
|
+
updatedAt: string;
|
|
29
|
+
}
|
|
30
|
+
export interface RevokeConsentResult {
|
|
31
|
+
ok: boolean;
|
|
32
|
+
/** Access tokens force-expired as part of the revocation. */
|
|
33
|
+
accessTokensExpired: number;
|
|
34
|
+
/** Unused authorization codes dropped as part of the revocation. */
|
|
35
|
+
codesDeleted: number;
|
|
36
|
+
}
|
|
37
|
+
export interface ApiKeyRecord {
|
|
38
|
+
/** Public handle — the middle segment of the credential. Safe to display and log. */
|
|
39
|
+
keyId: string;
|
|
40
|
+
name: string | null;
|
|
41
|
+
/** The bound user. Becomes the `sub` of every token this key mints. */
|
|
42
|
+
userId: string;
|
|
43
|
+
username: string;
|
|
44
|
+
createdBy: string;
|
|
45
|
+
createdAt: string;
|
|
46
|
+
/** null = never expires. */
|
|
47
|
+
expiresAt: string | null;
|
|
48
|
+
/** Non-null once revoked; the record is kept so the audit trail still resolves. */
|
|
49
|
+
revokedAt: string | null;
|
|
50
|
+
lastUsedAt: string | null;
|
|
51
|
+
}
|
|
52
|
+
export interface CreateApiKeyParams {
|
|
53
|
+
/** Internal user UUID or username to bind the key to. Required. */
|
|
54
|
+
userId: string;
|
|
55
|
+
/** Human-readable label, e.g. the pipeline that uses it. */
|
|
56
|
+
name?: string | null;
|
|
57
|
+
/** ISO timestamp. Omit for a key that never expires. */
|
|
58
|
+
expiresAt?: string | null;
|
|
59
|
+
/**
|
|
60
|
+
* Subset of the client's granted scopes. Omit for all of them. The subset is a
|
|
61
|
+
* snapshot: the key does not pick up scopes granted to the client later.
|
|
62
|
+
*/
|
|
63
|
+
scopes?: readonly string[];
|
|
64
|
+
}
|
|
65
|
+
export interface CreateApiKeyResult extends ApiKeyRecord {
|
|
66
|
+
/** The full credential. Returned only here — it cannot be recovered afterwards. */
|
|
67
|
+
apiKey: string;
|
|
68
|
+
}
|
|
21
69
|
export interface UpdateUserParams {
|
|
22
70
|
username?: string;
|
|
23
71
|
password?: string;
|
|
@@ -41,4 +89,38 @@ export declare function updateAdminUser(idOrUsername: string, updates: UpdateUse
|
|
|
41
89
|
* UUID or the username.
|
|
42
90
|
*/
|
|
43
91
|
export declare function deleteAdminUser(idOrUsername: string, config: AdminClientConfig): Promise<void>;
|
|
92
|
+
/**
|
|
93
|
+
* List the applications a user has authorized, with the scopes consented to for each.
|
|
94
|
+
* `idOrUsername` accepts either the internal UUID or the username.
|
|
95
|
+
*/
|
|
96
|
+
export declare function listUserConsents(idOrUsername: string, config: AdminClientConfig): Promise<AdminConsentRecord[]>;
|
|
97
|
+
/**
|
|
98
|
+
* Withdraw a user's consent for one client, addressed by its public `client_id`.
|
|
99
|
+
*
|
|
100
|
+
* This also revokes that user's refresh tokens, access tokens, and unused authorization
|
|
101
|
+
* codes for the client, so access stops immediately rather than at token expiry.
|
|
102
|
+
*/
|
|
103
|
+
export declare function revokeUserConsent(idOrUsername: string, clientId: string, config: AdminClientConfig): Promise<RevokeConsentResult>;
|
|
104
|
+
/**
|
|
105
|
+
* List every API key issued for a client, including revoked and expired ones.
|
|
106
|
+
*
|
|
107
|
+
* The secret is never returned — it is shown only once, when the key is created.
|
|
108
|
+
*/
|
|
109
|
+
export declare function listClientApiKeys(clientId: string, config: AdminClientConfig): Promise<ApiKeyRecord[]>;
|
|
110
|
+
/**
|
|
111
|
+
* Issue an API key for a client, bound to a user.
|
|
112
|
+
*
|
|
113
|
+
* The full credential comes back in `apiKey` and is not recoverable afterwards — store
|
|
114
|
+
* it at the call site or hand it straight to the operator.
|
|
115
|
+
*/
|
|
116
|
+
export declare function createClientApiKey(clientId: string, params: CreateApiKeyParams, config: AdminClientConfig): Promise<CreateApiKeyResult>;
|
|
117
|
+
/**
|
|
118
|
+
* Revoke an API key, addressed by its public handle.
|
|
119
|
+
*
|
|
120
|
+
* Takes effect on the next exchange; access tokens already minted live out their
|
|
121
|
+
* remaining TTL. Idempotent — retrying keeps the original revocation timestamp.
|
|
122
|
+
*/
|
|
123
|
+
export declare function revokeClientApiKey(clientId: string, keyId: string, config: AdminClientConfig): Promise<{
|
|
124
|
+
ok: boolean;
|
|
125
|
+
}>;
|
|
44
126
|
//# sourceMappingURL=admin.d.ts.map
|
package/dist/admin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../src/admin.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;
|
|
1
|
+
{"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../src/admin.ts"],"names":[],"mappings":"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"}
|
package/dist/admin.js
CHANGED
|
@@ -6,6 +6,14 @@ function adminUsersUrl(baseUrl, idOrUsername) {
|
|
|
6
6
|
}
|
|
7
7
|
return `${trimmed}/api/admin/users/${encodeURIComponent(idOrUsername)}`;
|
|
8
8
|
}
|
|
9
|
+
function adminUserConsentsUrl(baseUrl, idOrUsername) {
|
|
10
|
+
return `${adminUsersUrl(baseUrl, idOrUsername)}/consents`;
|
|
11
|
+
}
|
|
12
|
+
function adminClientApiKeysUrl(baseUrl, clientId, keyId) {
|
|
13
|
+
const trimmed = baseUrl.replace(/\/+$/, "");
|
|
14
|
+
const base = `${trimmed}/api/admin/clients/${encodeURIComponent(clientId)}/api-keys`;
|
|
15
|
+
return keyId === undefined ? base : `${base}/${encodeURIComponent(keyId)}`;
|
|
16
|
+
}
|
|
9
17
|
async function parseError(res) {
|
|
10
18
|
const data = (await res.json().catch(() => ({})));
|
|
11
19
|
return new OAuthError(data.error ?? "server_error", data.error_description ?? `Admin API request failed: ${res.status}`);
|
|
@@ -67,4 +75,92 @@ export async function deleteAdminUser(idOrUsername, config) {
|
|
|
67
75
|
throw await parseError(res);
|
|
68
76
|
}
|
|
69
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* List the applications a user has authorized, with the scopes consented to for each.
|
|
80
|
+
* `idOrUsername` accepts either the internal UUID or the username.
|
|
81
|
+
*/
|
|
82
|
+
export async function listUserConsents(idOrUsername, config) {
|
|
83
|
+
const res = await fetch(adminUserConsentsUrl(config.baseUrl, idOrUsername), {
|
|
84
|
+
headers: { Authorization: `Bearer ${config.accessToken}` },
|
|
85
|
+
});
|
|
86
|
+
if (!res.ok) {
|
|
87
|
+
throw await parseError(res);
|
|
88
|
+
}
|
|
89
|
+
const data = (await res.json());
|
|
90
|
+
return data.consents;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Withdraw a user's consent for one client, addressed by its public `client_id`.
|
|
94
|
+
*
|
|
95
|
+
* This also revokes that user's refresh tokens, access tokens, and unused authorization
|
|
96
|
+
* codes for the client, so access stops immediately rather than at token expiry.
|
|
97
|
+
*/
|
|
98
|
+
export async function revokeUserConsent(idOrUsername, clientId, config) {
|
|
99
|
+
const url = new URL(adminUserConsentsUrl(config.baseUrl, idOrUsername));
|
|
100
|
+
url.searchParams.set("client_id", clientId);
|
|
101
|
+
const res = await fetch(url.toString(), {
|
|
102
|
+
method: "DELETE",
|
|
103
|
+
headers: { Authorization: `Bearer ${config.accessToken}` },
|
|
104
|
+
});
|
|
105
|
+
if (!res.ok) {
|
|
106
|
+
throw await parseError(res);
|
|
107
|
+
}
|
|
108
|
+
return res.json();
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* List every API key issued for a client, including revoked and expired ones.
|
|
112
|
+
*
|
|
113
|
+
* The secret is never returned — it is shown only once, when the key is created.
|
|
114
|
+
*/
|
|
115
|
+
export async function listClientApiKeys(clientId, config) {
|
|
116
|
+
const res = await fetch(adminClientApiKeysUrl(config.baseUrl, clientId), {
|
|
117
|
+
headers: { Authorization: `Bearer ${config.accessToken}` },
|
|
118
|
+
});
|
|
119
|
+
if (!res.ok) {
|
|
120
|
+
throw await parseError(res);
|
|
121
|
+
}
|
|
122
|
+
const data = (await res.json());
|
|
123
|
+
return data.apiKeys;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Issue an API key for a client, bound to a user.
|
|
127
|
+
*
|
|
128
|
+
* The full credential comes back in `apiKey` and is not recoverable afterwards — store
|
|
129
|
+
* it at the call site or hand it straight to the operator.
|
|
130
|
+
*/
|
|
131
|
+
export async function createClientApiKey(clientId, params, config) {
|
|
132
|
+
const res = await fetch(adminClientApiKeysUrl(config.baseUrl, clientId), {
|
|
133
|
+
method: "POST",
|
|
134
|
+
headers: {
|
|
135
|
+
Authorization: `Bearer ${config.accessToken}`,
|
|
136
|
+
"Content-Type": "application/json",
|
|
137
|
+
},
|
|
138
|
+
body: JSON.stringify({
|
|
139
|
+
userId: params.userId,
|
|
140
|
+
...(params.name !== undefined ? { name: params.name } : {}),
|
|
141
|
+
...(params.expiresAt !== undefined ? { expiresAt: params.expiresAt } : {}),
|
|
142
|
+
...(params.scopes !== undefined ? { scopes: [...params.scopes] } : {}),
|
|
143
|
+
}),
|
|
144
|
+
});
|
|
145
|
+
if (!res.ok) {
|
|
146
|
+
throw await parseError(res);
|
|
147
|
+
}
|
|
148
|
+
return res.json();
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Revoke an API key, addressed by its public handle.
|
|
152
|
+
*
|
|
153
|
+
* Takes effect on the next exchange; access tokens already minted live out their
|
|
154
|
+
* remaining TTL. Idempotent — retrying keeps the original revocation timestamp.
|
|
155
|
+
*/
|
|
156
|
+
export async function revokeClientApiKey(clientId, keyId, config) {
|
|
157
|
+
const res = await fetch(adminClientApiKeysUrl(config.baseUrl, clientId, keyId), {
|
|
158
|
+
method: "DELETE",
|
|
159
|
+
headers: { Authorization: `Bearer ${config.accessToken}` },
|
|
160
|
+
});
|
|
161
|
+
if (!res.ok) {
|
|
162
|
+
throw await parseError(res);
|
|
163
|
+
}
|
|
164
|
+
return res.json();
|
|
165
|
+
}
|
|
70
166
|
//# sourceMappingURL=admin.js.map
|
package/dist/admin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin.js","sourceRoot":"","sources":["../src/admin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"admin.js","sourceRoot":"","sources":["../src/admin.ts"],"names":[],"mappings":"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"}
|