@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/dist/api.d.ts CHANGED
@@ -1,31 +1,160 @@
1
1
  import type { TokenResponse, UserInfoResponse, TokenValidationResponse } from "./types.js";
2
2
  export declare class OAuthError extends Error {
3
3
  readonly code: string;
4
- constructor(code: string, message: string);
4
+ /** HTTP status of the failed response, when the error came from one. */
5
+ readonly status?: number | undefined;
6
+ /** The server's `error_description`, when present. */
7
+ readonly description?: string | undefined;
8
+ constructor(code: string, message: string,
9
+ /** HTTP status of the failed response, when the error came from one. */
10
+ status?: number | undefined,
11
+ /** The server's `error_description`, when present. */
12
+ description?: string | undefined);
13
+ /**
14
+ * True when the access token was valid but lacked a required scope (HTTP 403
15
+ * `insufficient_scope`) — e.g. calling `/userinfo` with a token that was not
16
+ * granted `openid`. Re-authorize requesting the missing scope rather than
17
+ * treating the token as invalid.
18
+ */
19
+ get isInsufficientScope(): boolean;
5
20
  }
6
21
  export type GrantType = "authorization_code" | "client_credentials" | "refresh_token";
22
+ export interface AuthorizationUrlParams {
23
+ clientId: string;
24
+ redirectUri: string;
25
+ /** PKCE S256 challenge (required by this server). */
26
+ codeChallenge: string;
27
+ /** Space-delimited scope string. Merged with `scopes` if both are given. */
28
+ scope?: string;
29
+ /**
30
+ * Scopes as an array (e.g. `[OIDCScope.OpenId, OIDCScope.Profile]`). Merged
31
+ * with `scope`, de-duplicated. Prefer this with the `OIDCScope` constants so
32
+ * `openid` can't be dropped by a typo.
33
+ */
34
+ scopes?: readonly string[];
35
+ state?: string;
36
+ /** OIDC nonce, bound into the issued id_token for replay protection. */
37
+ nonce?: string;
38
+ /**
39
+ * RFC 8707 resource indicator: the protected-resource URL the token is for. The server
40
+ * binds the access token's `aud` to this value (instead of the client_id). Pass the same
41
+ * value to {@link exchangeToken}.
42
+ */
43
+ resource?: string;
44
+ }
45
+ /**
46
+ * Build an authorization-request URL for the authorization_code + PKCE flow.
47
+ * Includes the OIDC `nonce` and RFC 8707 `resource` when provided.
48
+ */
49
+ export declare function buildAuthorizationUrl(authorizationEndpoint: string, params: AuthorizationUrlParams): string;
7
50
  export interface ExchangeTokenParams {
8
51
  grantType: GrantType;
9
52
  clientId: string;
10
53
  clientSecret?: string;
54
+ /** Space-delimited scope string. Merged with `scopes` if both are given. */
11
55
  scope?: string;
56
+ /** Scopes as an array (e.g. with the `OIDCScope` constants). Merged with `scope`. */
57
+ scopes?: readonly string[];
12
58
  code?: string;
13
59
  redirectUri?: string;
14
60
  codeVerifier?: string;
15
61
  refreshToken?: string;
62
+ /**
63
+ * RFC 8707 resource indicator. When provided it must match the value sent to
64
+ * {@link buildAuthorizationUrl} (the server rejects a mismatch with `invalid_target`).
65
+ */
66
+ resource?: string;
16
67
  }
17
68
  export interface ExchangeTokenConfig {
18
69
  tokenEndpoint: string;
19
70
  }
20
71
  export declare function exchangeToken(params: ExchangeTokenParams, config: ExchangeTokenConfig): Promise<TokenResponse>;
72
+ export interface ExchangeApiKeyParams {
73
+ /** The full credential, `eak_<keyId>_<secret>`. */
74
+ apiKey: string;
75
+ /**
76
+ * Space-delimited subset of the key's scopes. Omit for all of them. Scopes outside
77
+ * the key's set are rejected, never granted.
78
+ */
79
+ scope?: string;
80
+ /** Scopes as an array. Merged with `scope`. */
81
+ scopes?: readonly string[];
82
+ /** RFC 8707 resource indicator; becomes the token's audience. */
83
+ resource?: string;
84
+ }
85
+ export interface ExchangeApiKeyConfig {
86
+ /** Usually `${issuer}/api/token/api-key`. */
87
+ apiKeyEndpoint: string;
88
+ }
89
+ /**
90
+ * Exchange a long-lived API key for a short-lived access token.
91
+ *
92
+ * Intended for CI/CD and other machine callers: one durable secret in the environment
93
+ * instead of a client_id + client_secret pair, and no client_credentials round trip
94
+ * before every request.
95
+ *
96
+ * The returned token carries the user the key is bound to as its `sub`. There is no
97
+ * `refresh_token` — the API key is itself the long-lived credential.
98
+ */
99
+ export declare function exchangeApiKey(params: ExchangeApiKeyParams, config: ExchangeApiKeyConfig): Promise<TokenResponse>;
21
100
  export interface IntrospectTokenParams {
22
101
  token: string;
23
102
  scopes?: string[];
24
103
  environmentName: string;
104
+ /**
105
+ * Optional audience binding. When set to the calling resource server's own
106
+ * client_id, the token is only reported valid if it was issued to that client —
107
+ * preventing a token minted for a sibling client in the same environment from
108
+ * being accepted here. Omit to keep the previous (audience-agnostic) behavior.
109
+ */
110
+ clientId?: string;
25
111
  }
26
112
  export interface IntrospectTokenConfig {
27
113
  introspectionEndpoint: string;
28
114
  }
29
115
  export declare function introspectToken(params: IntrospectTokenParams, config: IntrospectTokenConfig): Promise<TokenValidationResponse>;
116
+ export interface RegisterClientParams {
117
+ /** Human-readable name shown on the consent screen. */
118
+ clientName?: string;
119
+ /**
120
+ * Required. Exact-match https URLs; http is allowed only on a loopback host
121
+ * (`localhost`, any 127.0.0.0/8 address, or `[::1]`). At `/authorize` the loopback host is
122
+ * matched interchangeably — scheme, port, path, and query still have to match exactly.
123
+ */
124
+ redirectUris: string[];
125
+ /** Defaults server-side to `none` (public/PKCE). Use a confidential method for a secret. */
126
+ tokenEndpointAuthMethod?: "none" | "client_secret_basic" | "client_secret_post";
127
+ /** Defaults server-side to `["authorization_code", "refresh_token"]`. */
128
+ grantTypes?: string[];
129
+ /** Defaults server-side to `["code"]`. */
130
+ responseTypes?: string[];
131
+ /** Space-delimited scope string. Merged with `scopes` if both are given. */
132
+ scope?: string;
133
+ /** Scopes as an array (e.g. with the `OIDCScope` constants). Merged with `scope`. */
134
+ scopes?: readonly string[];
135
+ }
136
+ export interface RegisterClientConfig {
137
+ /** The `registration_endpoint` from discovery metadata. */
138
+ registrationEndpoint: string;
139
+ }
140
+ /** RFC 7591 client registration response. `client_secret` is present only for confidential clients. */
141
+ export interface RegisterClientResponse {
142
+ client_id: string;
143
+ client_id_issued_at: number;
144
+ redirect_uris: string[];
145
+ grant_types: string[];
146
+ response_types: string[];
147
+ token_endpoint_auth_method: string;
148
+ scope?: string;
149
+ client_secret?: string;
150
+ client_secret_expires_at?: number;
151
+ }
152
+ /**
153
+ * Dynamically register an OAuth client (RFC 7591) at the server's `registration_endpoint`.
154
+ * Public clients (`tokenEndpointAuthMethod: "none"`, the default) get no secret and use PKCE.
155
+ * Throws {@link OAuthError} on a non-2xx response (e.g. `invalid_redirect_uri`,
156
+ * `invalid_client_metadata`, or `too_many_requests` when rate-limited).
157
+ */
158
+ export declare function registerClient(params: RegisterClientParams, config: RegisterClientConfig): Promise<RegisterClientResponse>;
30
159
  export declare function getUserInfo(accessToken: string, userInfoEndpoint: string): Promise<UserInfoResponse>;
31
160
  //# sourceMappingURL=api.d.ts.map
package/dist/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE3F,qBAAa,UAAW,SAAQ,KAAK;aAEjB,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM;CAKlB;AAED,MAAM,MAAM,SAAS,GAAG,oBAAoB,GAAG,oBAAoB,GAAG,eAAe,CAAC;AAEtF,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,mBAAmB,EAC3B,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,aAAa,CAAC,CA2BxB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,qBAAqB,EAC7B,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,uBAAuB,CAAC,CAWlC;AAED,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,EACnB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,gBAAgB,CAAC,CAY3B"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
package/dist/api.js CHANGED
@@ -1,10 +1,50 @@
1
+ import { resolveScopeParam } from "./scopes.js";
1
2
  export class OAuthError extends Error {
2
3
  code;
3
- constructor(code, message) {
4
+ status;
5
+ description;
6
+ constructor(code, message,
7
+ /** HTTP status of the failed response, when the error came from one. */
8
+ status,
9
+ /** The server's `error_description`, when present. */
10
+ description) {
4
11
  super(message);
5
12
  this.code = code;
13
+ this.status = status;
14
+ this.description = description;
6
15
  this.name = "OAuthError";
7
16
  }
17
+ /**
18
+ * True when the access token was valid but lacked a required scope (HTTP 403
19
+ * `insufficient_scope`) — e.g. calling `/userinfo` with a token that was not
20
+ * granted `openid`. Re-authorize requesting the missing scope rather than
21
+ * treating the token as invalid.
22
+ */
23
+ get isInsufficientScope() {
24
+ return this.code === "insufficient_scope";
25
+ }
26
+ }
27
+ /**
28
+ * Build an authorization-request URL for the authorization_code + PKCE flow.
29
+ * Includes the OIDC `nonce` and RFC 8707 `resource` when provided.
30
+ */
31
+ export function buildAuthorizationUrl(authorizationEndpoint, params) {
32
+ const url = new URL(authorizationEndpoint);
33
+ url.searchParams.set("response_type", "code");
34
+ url.searchParams.set("client_id", params.clientId);
35
+ url.searchParams.set("redirect_uri", params.redirectUri);
36
+ url.searchParams.set("code_challenge", params.codeChallenge);
37
+ url.searchParams.set("code_challenge_method", "S256");
38
+ const scope = resolveScopeParam(params.scope, params.scopes);
39
+ if (scope)
40
+ url.searchParams.set("scope", scope);
41
+ if (params.state)
42
+ url.searchParams.set("state", params.state);
43
+ if (params.nonce)
44
+ url.searchParams.set("nonce", params.nonce);
45
+ if (params.resource)
46
+ url.searchParams.set("resource", params.resource);
47
+ return url.toString();
8
48
  }
9
49
  export async function exchangeToken(params, config) {
10
50
  const body = new URLSearchParams();
@@ -12,8 +52,9 @@ export async function exchangeToken(params, config) {
12
52
  body.set("client_id", params.clientId);
13
53
  if (params.clientSecret)
14
54
  body.set("client_secret", params.clientSecret);
15
- if (params.scope)
16
- body.set("scope", params.scope);
55
+ const scope = resolveScopeParam(params.scope, params.scopes);
56
+ if (scope)
57
+ body.set("scope", scope);
17
58
  if (params.code)
18
59
  body.set("code", params.code);
19
60
  if (params.redirectUri)
@@ -22,6 +63,8 @@ export async function exchangeToken(params, config) {
22
63
  body.set("code_verifier", params.codeVerifier);
23
64
  if (params.refreshToken)
24
65
  body.set("refresh_token", params.refreshToken);
66
+ if (params.resource)
67
+ body.set("resource", params.resource);
25
68
  const res = await fetch(config.tokenEndpoint, {
26
69
  method: "POST",
27
70
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
@@ -33,6 +76,39 @@ export async function exchangeToken(params, config) {
33
76
  }
34
77
  return data;
35
78
  }
79
+ /**
80
+ * Exchange a long-lived API key for a short-lived access token.
81
+ *
82
+ * Intended for CI/CD and other machine callers: one durable secret in the environment
83
+ * instead of a client_id + client_secret pair, and no client_credentials round trip
84
+ * before every request.
85
+ *
86
+ * The returned token carries the user the key is bound to as its `sub`. There is no
87
+ * `refresh_token` — the API key is itself the long-lived credential.
88
+ */
89
+ export async function exchangeApiKey(params, config) {
90
+ const body = new URLSearchParams();
91
+ const scope = resolveScopeParam(params.scope, params.scopes);
92
+ if (scope)
93
+ body.set("scope", scope);
94
+ if (params.resource)
95
+ body.set("resource", params.resource);
96
+ const res = await fetch(config.apiKeyEndpoint, {
97
+ method: "POST",
98
+ headers: {
99
+ // Sent as a bearer credential rather than in the body so the key stays out of
100
+ // anything that logs request bodies.
101
+ Authorization: `Bearer ${params.apiKey}`,
102
+ "Content-Type": "application/x-www-form-urlencoded",
103
+ },
104
+ body,
105
+ });
106
+ const data = (await res.json());
107
+ if (!res.ok) {
108
+ throw new OAuthError(data.error ?? "server_error", data.error_description ?? `API key exchange failed: ${res.status}`, res.status, data.error_description);
109
+ }
110
+ return data;
111
+ }
36
112
  export async function introspectToken(params, config) {
37
113
  const res = await fetch(config.introspectionEndpoint, {
38
114
  method: "POST",
@@ -41,17 +117,57 @@ export async function introspectToken(params, config) {
41
117
  token: params.token,
42
118
  scopes: params.scopes ?? [],
43
119
  environmentName: params.environmentName,
120
+ ...(params.clientId ? { clientId: params.clientId } : {}),
44
121
  }),
45
122
  });
46
123
  return res.json();
47
124
  }
125
+ /**
126
+ * Dynamically register an OAuth client (RFC 7591) at the server's `registration_endpoint`.
127
+ * Public clients (`tokenEndpointAuthMethod: "none"`, the default) get no secret and use PKCE.
128
+ * Throws {@link OAuthError} on a non-2xx response (e.g. `invalid_redirect_uri`,
129
+ * `invalid_client_metadata`, or `too_many_requests` when rate-limited).
130
+ */
131
+ export async function registerClient(params, config) {
132
+ const requestBody = { redirect_uris: params.redirectUris };
133
+ if (params.clientName)
134
+ requestBody.client_name = params.clientName;
135
+ if (params.tokenEndpointAuthMethod)
136
+ requestBody.token_endpoint_auth_method = params.tokenEndpointAuthMethod;
137
+ if (params.grantTypes)
138
+ requestBody.grant_types = params.grantTypes;
139
+ if (params.responseTypes)
140
+ requestBody.response_types = params.responseTypes;
141
+ const scope = resolveScopeParam(params.scope, params.scopes);
142
+ if (scope)
143
+ requestBody.scope = scope;
144
+ const res = await fetch(config.registrationEndpoint, {
145
+ method: "POST",
146
+ headers: { "Content-Type": "application/json" },
147
+ body: JSON.stringify(requestBody),
148
+ });
149
+ const data = (await res.json().catch(() => ({})));
150
+ if (!res.ok) {
151
+ throw new OAuthError(data.error ?? "server_error", data.error_description ?? `Client registration failed: ${res.status}`, res.status, data.error_description);
152
+ }
153
+ return data;
154
+ }
48
155
  export async function getUserInfo(accessToken, userInfoEndpoint) {
49
156
  const res = await fetch(userInfoEndpoint, {
50
157
  headers: { Authorization: `Bearer ${accessToken}` },
51
158
  });
52
159
  if (!res.ok) {
53
160
  const data = (await res.json().catch(() => ({})));
54
- throw new OAuthError(data.error ?? "invalid_token", `UserInfo request failed: ${res.status}`);
161
+ // A 403 means the token is valid but missing a required scope (`openid`).
162
+ // Surface it as `insufficient_scope` so callers can re-authorize with the
163
+ // right scopes instead of discarding the token as invalid. A 401 (or a
164
+ // non-JSON body) stays `invalid_token`.
165
+ const code = data.error ?? (res.status === 403 ? "insufficient_scope" : "invalid_token");
166
+ const message = data.error_description ??
167
+ (code === "insufficient_scope"
168
+ ? "UserInfo requires the openid scope on the access token."
169
+ : `UserInfo request failed: ${res.status}`);
170
+ throw new OAuthError(code, message, res.status, data.error_description);
55
171
  }
56
172
  return res.json();
57
173
  }
package/dist/api.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,12 +1,15 @@
1
- export type { TokenResponse, UserInfoResponse, OIDCDiscovery, OAuthServerMetadata, AuthClientConfig, JWTPayload, TokenValidationResponse, } from "./types.js";
1
+ export type { TokenResponse, UserInfoResponse, UserProfile, OIDCDiscovery, OAuthServerMetadata, AuthClientConfig, JWTPayload, IDTokenClaims, TokenValidationResponse, } from "./types.js";
2
+ export { OIDCScope, STANDARD_OIDC_SCOPES, resolveScopeParam, } from "./scopes.js";
3
+ export type { OIDCScopeValue } from "./scopes.js";
4
+ export { toUserProfile } from "./profile.js";
2
5
  export { fetchOIDCDiscovery, fetchOAuthMetadata } from "./discovery.js";
3
- export { OAuthError, exchangeToken, introspectToken, getUserInfo, } from "./api.js";
4
- export type { GrantType, ExchangeTokenParams, ExchangeTokenConfig, IntrospectTokenParams, IntrospectTokenConfig, } from "./api.js";
6
+ export { OAuthError, exchangeToken, introspectToken, getUserInfo, buildAuthorizationUrl, registerClient, exchangeApiKey, } from "./api.js";
7
+ export type { GrantType, ExchangeTokenParams, ExchangeTokenConfig, IntrospectTokenParams, IntrospectTokenConfig, AuthorizationUrlParams, RegisterClientParams, RegisterClientConfig, RegisterClientResponse, ExchangeApiKeyParams, ExchangeApiKeyConfig, } from "./api.js";
5
8
  export { TokenManager } from "./tokens.js";
6
- export { validateJwt, decodeJwtPayload } from "./jwt.js";
7
- export type { ValidateJwtOptions } from "./jwt.js";
8
- export { getAdminUser, createAdminUser, updateAdminUser, deleteAdminUser, } from "./admin.js";
9
- export type { AdminUserRecord, AdminClientConfig, CreateUserParams, UpdateUserParams, } from "./admin.js";
9
+ export { validateJwt, validateIdToken, decodeJwtPayload } from "./jwt.js";
10
+ export type { ValidateJwtOptions, ValidateIdTokenOptions } from "./jwt.js";
11
+ export { getAdminUser, createAdminUser, updateAdminUser, deleteAdminUser, listUserConsents, revokeUserConsent, listClientApiKeys, createClientApiKey, revokeClientApiKey, } from "./admin.js";
12
+ export type { AdminUserRecord, AdminClientConfig, AdminConsentRecord, RevokeConsentResult, CreateUserParams, UpdateUserParams, ApiKeyRecord, CreateApiKeyParams, CreateApiKeyResult, } from "./admin.js";
10
13
  export { listPasskeys, renamePasskey, removePasskey } from "./passkeys.js";
11
14
  export type { PasskeySummary, UserClientConfig } from "./passkeys.js";
12
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,EACV,uBAAuB,GACxB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAExE,OAAO,EACL,UAAU,EACV,aAAa,EACb,eAAe,EACf,WAAW,GACZ,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,SAAS,EACT,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACzD,YAAY,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAEnD,OAAO,EACL,YAAY,EACZ,eAAe,EACf,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC3E,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,uBAAuB,GACxB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,SAAS,EACT,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAExE,OAAO,EACL,UAAU,EACV,aAAa,EACb,eAAe,EACf,WAAW,EACX,qBAAqB,EACrB,cAAc,EACd,cAAc,GACf,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,SAAS,EACT,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC1E,YAAY,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAE3E,OAAO,EACL,YAAY,EACZ,eAAe,EACf,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC3E,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
+ export { OIDCScope, STANDARD_OIDC_SCOPES, resolveScopeParam, } from "./scopes.js";
2
+ export { toUserProfile } from "./profile.js";
1
3
  export { fetchOIDCDiscovery, fetchOAuthMetadata } from "./discovery.js";
2
- export { OAuthError, exchangeToken, introspectToken, getUserInfo, } from "./api.js";
4
+ export { OAuthError, exchangeToken, introspectToken, getUserInfo, buildAuthorizationUrl, registerClient, exchangeApiKey, } from "./api.js";
3
5
  export { TokenManager } from "./tokens.js";
4
- export { validateJwt, decodeJwtPayload } from "./jwt.js";
5
- export { getAdminUser, createAdminUser, updateAdminUser, deleteAdminUser, } from "./admin.js";
6
+ export { validateJwt, validateIdToken, decodeJwtPayload } from "./jwt.js";
7
+ export { getAdminUser, createAdminUser, updateAdminUser, deleteAdminUser, listUserConsents, revokeUserConsent, listClientApiKeys, createClientApiKey, revokeClientApiKey, } from "./admin.js";
6
8
  export { listPasskeys, renamePasskey, removePasskey } from "./passkeys.js";
7
9
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAExE,OAAO,EACL,UAAU,EACV,aAAa,EACb,eAAe,EACf,WAAW,GACZ,MAAM,UAAU,CAAC;AASlB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAGzD,OAAO,EACL,YAAY,EACZ,eAAe,EACf,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AAQpB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,OAAO,EACL,SAAS,EACT,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAExE,OAAO,EACL,UAAU,EACV,aAAa,EACb,eAAe,EACf,WAAW,EACX,qBAAqB,EACrB,cAAc,EACd,cAAc,GACf,MAAM,UAAU,CAAC;AAelB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAG1E,OAAO,EACL,YAAY,EACZ,eAAe,EACf,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AAapB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
package/dist/jwt.d.ts CHANGED
@@ -1,9 +1,19 @@
1
- import type { JWTPayload } from "./types.js";
1
+ import type { IDTokenClaims, JWTPayload } from "./types.js";
2
2
  export interface ValidateJwtOptions {
3
3
  audience?: string | string[];
4
4
  issuer?: string;
5
5
  clockTolerance?: number;
6
6
  }
7
+ export interface ValidateIdTokenOptions extends ValidateJwtOptions {
8
+ /** When set, the id_token's `nonce` claim must match this value (OIDC replay defense). */
9
+ nonce?: string;
10
+ }
7
11
  export declare function validateJwt(token: string, jwksUri: string, options?: ValidateJwtOptions): Promise<JWTPayload>;
12
+ /**
13
+ * Verify an OIDC id_token: checks the RS256 signature against the JWKS plus
14
+ * `iss`/`aud`/`exp` (via {@link validateJwt}), and — when `options.nonce` is
15
+ * supplied — that the token's `nonce` claim matches, defending against replay.
16
+ */
17
+ export declare function validateIdToken(token: string, jwksUri: string, options?: ValidateIdTokenOptions): Promise<IDTokenClaims>;
8
18
  export declare function decodeJwtPayload(token: string): JWTPayload;
9
19
  //# sourceMappingURL=jwt.d.ts.map
package/dist/jwt.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../src/jwt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAWD,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,UAAU,CAAC,CAQrB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAQ1D"}
1
+ {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../src/jwt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE5D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,sBAAuB,SAAQ,kBAAkB;IAChE,0FAA0F;IAC1F,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAWD,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,UAAU,CAAC,CAQrB;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,aAAa,CAAC,CAOxB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAQ1D"}
package/dist/jwt.js CHANGED
@@ -15,6 +15,19 @@ export async function validateJwt(token, jwksUri, options = {}) {
15
15
  });
16
16
  return payload;
17
17
  }
18
+ /**
19
+ * Verify an OIDC id_token: checks the RS256 signature against the JWKS plus
20
+ * `iss`/`aud`/`exp` (via {@link validateJwt}), and — when `options.nonce` is
21
+ * supplied — that the token's `nonce` claim matches, defending against replay.
22
+ */
23
+ export async function validateIdToken(token, jwksUri, options = {}) {
24
+ const { nonce, ...jwtOptions } = options;
25
+ const payload = (await validateJwt(token, jwksUri, jwtOptions));
26
+ if (nonce !== undefined && payload.nonce !== nonce) {
27
+ throw new Error("id_token nonce mismatch");
28
+ }
29
+ return payload;
30
+ }
18
31
  export function decodeJwtPayload(token) {
19
32
  const parts = token.split(".");
20
33
  if (parts.length !== 3) {
package/dist/jwt.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"jwt.js","sourceRoot":"","sources":["../src/jwt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AASrD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAiD,CAAC;AAE3E,SAAS,OAAO,CAAC,OAAe;IAC9B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,kBAAkB,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,SAAS,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC;AACjC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAa,EACb,OAAe,EACf,UAA8B,EAAE;IAEhC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE;QAC/C,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,CAAC;KAC5C,CAAC,CAAC;IACH,OAAO,OAAqB,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC5D,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAe,CAAC;AACxC,CAAC"}
1
+ {"version":3,"file":"jwt.js","sourceRoot":"","sources":["../src/jwt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAcrD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAiD,CAAC;AAE3E,SAAS,OAAO,CAAC,OAAe;IAC9B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,kBAAkB,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,SAAS,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC;AACjC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAa,EACb,OAAe,EACf,UAA8B,EAAE;IAEhC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE;QAC/C,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,CAAC;KAC5C,CAAC,CAAC;IACH,OAAO,OAAqB,CAAC;AAC/B,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,KAAa,EACb,OAAe,EACf,UAAkC,EAAE;IAEpC,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,EAAE,GAAG,OAAO,CAAC;IACzC,MAAM,OAAO,GAAG,CAAC,MAAM,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAkB,CAAC;IACjF,IAAI,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC5D,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAe,CAAC;AACxC,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { IDTokenClaims, UserInfoResponse, UserProfile } from "./types.js";
2
+ /**
3
+ * Merge `/userinfo` claims (and optionally id_token claims) into a normalized,
4
+ * camelCased {@link UserProfile}. UserInfo values take precedence over id_token
5
+ * values — UserInfo is the authoritative, freshest source — and the id_token
6
+ * fills any gap for claims `/userinfo` did not return.
7
+ *
8
+ * Fields stay optional because the server only returns claims the access token's
9
+ * scopes allow (`profile` → name/preferredUsername/picture, `email` →
10
+ * email/emailVerified), so a profile built from an `openid`-only token carries
11
+ * just `sub`.
12
+ */
13
+ export declare function toUserProfile(userInfo: UserInfoResponse, idTokenClaims?: IDTokenClaims): UserProfile;
14
+ //# sourceMappingURL=profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE/E;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,gBAAgB,EAC1B,aAAa,CAAC,EAAE,aAAa,GAC5B,WAAW,CAcb"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Merge `/userinfo` claims (and optionally id_token claims) into a normalized,
3
+ * camelCased {@link UserProfile}. UserInfo values take precedence over id_token
4
+ * values — UserInfo is the authoritative, freshest source — and the id_token
5
+ * fills any gap for claims `/userinfo` did not return.
6
+ *
7
+ * Fields stay optional because the server only returns claims the access token's
8
+ * scopes allow (`profile` → name/preferredUsername/picture, `email` →
9
+ * email/emailVerified), so a profile built from an `openid`-only token carries
10
+ * just `sub`.
11
+ */
12
+ export function toUserProfile(userInfo, idTokenClaims) {
13
+ const prefer = (primary, fallback) => primary !== undefined ? primary : fallback;
14
+ return {
15
+ sub: userInfo.sub ?? idTokenClaims?.sub ?? "",
16
+ name: prefer(userInfo.name, idTokenClaims?.name),
17
+ preferredUsername: prefer(userInfo.preferred_username, idTokenClaims?.preferred_username),
18
+ picture: prefer(userInfo.picture, idTokenClaims?.picture),
19
+ email: prefer(userInfo.email, idTokenClaims?.email),
20
+ emailVerified: prefer(userInfo.email_verified, idTokenClaims?.email_verified),
21
+ };
22
+ }
23
+ //# sourceMappingURL=profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.js","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAC3B,QAA0B,EAC1B,aAA6B;IAE7B,MAAM,MAAM,GAAG,CAAI,OAAsB,EAAE,QAAuB,EAAiB,EAAE,CACnF,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC7C,OAAO;QACL,GAAG,EAAE,QAAQ,CAAC,GAAG,IAAI,aAAa,EAAE,GAAG,IAAI,EAAE;QAC7C,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,CAAC;QAChD,iBAAiB,EAAE,MAAM,CACvB,QAAQ,CAAC,kBAAkB,EAC3B,aAAa,EAAE,kBAAkB,CAClC;QACD,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,CAAC;QACzD,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,CAAC;QACnD,aAAa,EAAE,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE,aAAa,EAAE,cAAc,CAAC;KAC9E,CAAC;AACJ,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Standard OpenID Connect scopes recognized by the eetr-auth server. These are seeded
3
+ * on install; an admin still grants them to each client. Use them when building an
4
+ * authorization request or token exchange so a typo can't silently drop `openid` (which
5
+ * would make `/userinfo` return 403 insufficient_scope).
6
+ */
7
+ export declare const OIDCScope: {
8
+ /** Required to mint an id_token and to call the `/userinfo` endpoint. */
9
+ readonly OpenId: "openid";
10
+ /** Gates the `name` / `preferred_username` / `picture` claims. */
11
+ readonly Profile: "profile";
12
+ /** Gates the `email` / `email_verified` claims. */
13
+ readonly Email: "email";
14
+ };
15
+ export type OIDCScopeValue = (typeof OIDCScope)[keyof typeof OIDCScope];
16
+ /** The standard OIDC scopes, in canonical order: `openid profile email`. */
17
+ export declare const STANDARD_OIDC_SCOPES: readonly OIDCScopeValue[];
18
+ /**
19
+ * Merge a free-form `scope` string and/or a `scopes` array into a single
20
+ * space-delimited scope string, trimmed, de-duplicated, and order-preserving
21
+ * (the `scope` string first, then `scopes`). Returns `undefined` when neither
22
+ * yields any scope, so callers can omit the parameter entirely.
23
+ */
24
+ export declare function resolveScopeParam(scope?: string, scopes?: readonly string[]): string | undefined;
25
+ //# sourceMappingURL=scopes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopes.d.ts","sourceRoot":"","sources":["../src/scopes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,SAAS;IACpB,yEAAyE;;IAEzE,kEAAkE;;IAElE,mDAAmD;;CAE3C,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAExE,4EAA4E;AAC5E,eAAO,MAAM,oBAAoB,EAAE,SAAS,cAAc,EAIzD,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,CAAC,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GACzB,MAAM,GAAG,SAAS,CAapB"}
package/dist/scopes.js ADDED
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Standard OpenID Connect scopes recognized by the eetr-auth server. These are seeded
3
+ * on install; an admin still grants them to each client. Use them when building an
4
+ * authorization request or token exchange so a typo can't silently drop `openid` (which
5
+ * would make `/userinfo` return 403 insufficient_scope).
6
+ */
7
+ export const OIDCScope = {
8
+ /** Required to mint an id_token and to call the `/userinfo` endpoint. */
9
+ OpenId: "openid",
10
+ /** Gates the `name` / `preferred_username` / `picture` claims. */
11
+ Profile: "profile",
12
+ /** Gates the `email` / `email_verified` claims. */
13
+ Email: "email",
14
+ };
15
+ /** The standard OIDC scopes, in canonical order: `openid profile email`. */
16
+ export const STANDARD_OIDC_SCOPES = [
17
+ OIDCScope.OpenId,
18
+ OIDCScope.Profile,
19
+ OIDCScope.Email,
20
+ ];
21
+ /**
22
+ * Merge a free-form `scope` string and/or a `scopes` array into a single
23
+ * space-delimited scope string, trimmed, de-duplicated, and order-preserving
24
+ * (the `scope` string first, then `scopes`). Returns `undefined` when neither
25
+ * yields any scope, so callers can omit the parameter entirely.
26
+ */
27
+ export function resolveScopeParam(scope, scopes) {
28
+ const out = [];
29
+ const seen = new Set();
30
+ const add = (value) => {
31
+ const trimmed = value.trim();
32
+ if (trimmed && !seen.has(trimmed)) {
33
+ seen.add(trimmed);
34
+ out.push(trimmed);
35
+ }
36
+ };
37
+ if (scope)
38
+ scope.split(/\s+/).forEach(add);
39
+ if (scopes)
40
+ scopes.forEach(add);
41
+ return out.length > 0 ? out.join(" ") : undefined;
42
+ }
43
+ //# sourceMappingURL=scopes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopes.js","sourceRoot":"","sources":["../src/scopes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,yEAAyE;IACzE,MAAM,EAAE,QAAQ;IAChB,kEAAkE;IAClE,OAAO,EAAE,SAAS;IAClB,mDAAmD;IACnD,KAAK,EAAE,OAAO;CACN,CAAC;AAIX,4EAA4E;AAC5E,MAAM,CAAC,MAAM,oBAAoB,GAA8B;IAC7D,SAAS,CAAC,MAAM;IAChB,SAAS,CAAC,OAAO;IACjB,SAAS,CAAC,KAAK;CAChB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAc,EACd,MAA0B;IAE1B,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,GAAG,GAAG,CAAC,KAAa,EAAE,EAAE;QAC5B,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YAClC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAClB,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,CAAC;IACH,CAAC,CAAC;IACF,IAAI,KAAK;QAAE,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3C,IAAI,MAAM;QAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACpD,CAAC"}