@udibo/oauth2 0.25.0 → 0.27.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.
@@ -21,7 +21,7 @@
21
21
  * @module
22
22
  */
23
23
  import type { AuthorizeParameters } from "../models/authorization-code.ts";
24
- import type { AuthenticationContext } from "../models/authentication.ts";
24
+ import type { AuthenticationContext, AuthenticationRequest } from "../models/authentication.ts";
25
25
  import type { ClientInterface } from "../models/client.ts";
26
26
  import type { Token, TokenResponse } from "../models/token.ts";
27
27
  import type { AuthorizationServerMetadata } from "../models/responses.ts";
@@ -288,6 +288,32 @@ export interface AuthorizationServerOptions<Client extends ClientInterface, User
288
288
  * integer.
289
289
  */
290
290
  maxBodyBytes?: number;
291
+ /**
292
+ * The `prompt` values the authorization endpoint accepts, advertised as
293
+ * `prompt_values_supported`. A request carrying any other value is refused
294
+ * with `invalid_request`.
295
+ *
296
+ * The server enforces `none`, `login` and `consent` itself. List another
297
+ * value, such as `select_account` or `create`, only when your
298
+ * `authenticateUser` honors it: the server passes it through in the
299
+ * {@linkcode AuthenticationRequest} and cannot check the result.
300
+ *
301
+ * @default ["none", "login", "consent"]
302
+ * @throws {TypeError} From the constructor when an entry is empty or
303
+ * contains a space or non-ASCII character.
304
+ */
305
+ promptValuesSupported?: readonly string[];
306
+ /**
307
+ * Authentication context class references your `authenticateUser` can
308
+ * achieve, advertised as `acr_values_supported` in the OIDC discovery
309
+ * document. It does not restrict `acr_values`: the request's preferences
310
+ * reach `authenticateUser` either way, and the ID token's `acr` is what the
311
+ * returned `authenticationContext` records.
312
+ *
313
+ * @throws {TypeError} From the constructor when an entry is empty or
314
+ * contains a space or non-ASCII character.
315
+ */
316
+ acrValuesSupported?: readonly string[];
291
317
  }
292
318
  /**
293
319
  * Function to authenticate the user during authorization.
@@ -305,17 +331,29 @@ export interface AuthorizationServerOptions<Client extends ClientInterface, User
305
331
  * pre-authorize everything, return the requested scope as `authorizedScope`.
306
332
  * Supply only verified event claims in `authenticationContext`; the code,
307
333
  * token and refresh descendants retain a snapshot. Omit unknown claims.
334
+ * Set `reauthenticated: true` only when the user actively authenticated in
335
+ * response to this authorization request.
308
336
  * - `null` — explicit denial. The framework redirects the browser to
309
337
  * `redirect_uri` with `error=access_denied`. Use this for "the user said
310
338
  * no", not for "the user isn't signed in yet."
311
339
  * - A `Response` — short-circuits the rest of the authorize flow and is
312
340
  * returned to the browser as-is. Use this to redirect to a login page,
313
- * render an interstitial, etc.
341
+ * render an interstitial, etc. Under `prompt=none` the server answers
342
+ * `login_required` instead of returning it.
343
+ *
344
+ * The second argument carries the request's validated `prompt`, `max_age` and
345
+ * `acr_values`; the server always passes it. Before issuing a code the server
346
+ * checks the returned user against it with
347
+ * {@linkcode satisfiesAuthenticationRequest} and answers `login_required` when
348
+ * the check fails, so send the user to sign in again (return a `Response`)
349
+ * whenever the session cannot meet it. Report the `acr` the login achieved in
350
+ * `authenticationContext`, never the requested one.
314
351
  */
315
- export type AuthenticateUserFn<User> = (request: Request) => Promise<{
352
+ export type AuthenticateUserFn<User> = (request: Request, authentication?: AuthenticationRequest) => Promise<{
316
353
  user: User;
317
354
  authorizedScope?: AbstractScope;
318
355
  authenticationContext?: AuthenticationContext;
356
+ reauthenticated?: boolean;
319
357
  } | Response | null>;
320
358
  /**
321
359
  * Function to handle user consent during authorization.
@@ -330,9 +368,14 @@ export type AuthenticateUserFn<User> = (request: Request) => Promise<{
330
368
  * `redirect_uri` with `error=access_denied`.
331
369
  * - A `Response` — short-circuits the rest of the authorize flow and is
332
370
  * returned to the browser as-is. Use this to render a consent page that
333
- * later resubmits to the authorize endpoint with the user's decision.
371
+ * later resubmits to the authorize endpoint with the user's decision. Under
372
+ * `prompt=none` the server answers `consent_required` instead.
373
+ *
374
+ * With `prompt=consent` the server calls it even when the scope is already
375
+ * authorized, and the fourth argument, always passed, says so: ask again
376
+ * rather than reusing a stored grant.
334
377
  */
335
- export type HandleConsentFn<Client extends ClientInterface, S extends AbstractScope> = (client: Client, requestedScope: S | undefined, user: unknown) => Promise<{
378
+ export type HandleConsentFn<Client extends ClientInterface, S extends AbstractScope> = (client: Client, requestedScope: S | undefined, user: unknown, authentication?: AuthenticationRequest) => Promise<{
336
379
  approved: boolean;
337
380
  scope?: S;
338
381
  } | Response>;
@@ -450,7 +493,8 @@ export declare class AuthorizationServer<Client extends ClientInterface, User, S
450
493
  * @throws {RangeError} If `maxBodyBytes` or `maxTokenBodyBytes` is not a
451
494
  * positive integer.
452
495
  * @throws {TypeError} If `realm` contains a character outside printable
453
- * ASCII.
496
+ * ASCII, or a `promptValuesSupported` or `acrValuesSupported` entry is
497
+ * empty or contains a space or non-ASCII character.
454
498
  */
455
499
  constructor(options: AuthorizationServerOptions<Client, User, S>);
456
500
  /**
@@ -508,7 +552,9 @@ export declare class AuthorizationServer<Client extends ClientInterface, User, S
508
552
  * `openid`, or `undefined` when the OIDC surface is off (no signing keys),
509
553
  * the token has no user, the scope lacks `openid`, or no issuer resolved.
510
554
  * The id_token's `aud` is the client id and it expires one hour after
511
- * issue.
555
+ * issue. Its `auth_time` and `acr` are the token's recorded
556
+ * `authenticationContext`, present exactly when the context has them,
557
+ * whatever `userClaims` returns.
512
558
  */
513
559
  mintIdToken(token: Token<Client, User, S>, context: AuthorizationServerContext<Client, User, S>): Promise<string | undefined>;
514
560
  /**
@@ -610,6 +656,11 @@ export declare class AuthorizationServer<Client extends ClientInterface, User, S
610
656
  * responses from this endpoint, since there is no verified place to send the
611
657
  * user back to.
612
658
  *
659
+ * Every redirect to the client, the code and the error alike, carries `iss`
660
+ * set to the request's resolved issuer (RFC 9207), replacing any `iss` the
661
+ * registered `redirect_uri` itself carries. A request that resolves no
662
+ * `issuer` sends none.
663
+ *
613
664
  * Requires a grant extending {@linkcode AuthorizationCodeGrant} registered
614
665
  * under `authorization_code`; without one the endpoint answers 500
615
666
  * `server_error` (or rethrows, with `throwOnError`).
@@ -719,7 +770,9 @@ export declare class AuthorizationServer<Client extends ClientInterface, User, S
719
770
  * authorization code grant's own `challengeMethods`, so a server that
720
771
  * registers an extra method (or drops `S256`) advertises what it will
721
772
  * actually accept. It is omitted entirely when no authorization code grant
722
- * is registered, since PKCE has nothing to apply to.
773
+ * is registered, since PKCE has nothing to apply to. The same condition
774
+ * governs `authorization_response_iss_parameter_supported: true`
775
+ * (RFC 9207 §3): the authorization endpoint's redirects carry `iss`.
723
776
  *
724
777
  * `token_endpoint_auth_methods_supported` always includes `none`, the
725
778
  * RFC 7591 method for a client with no secret. The token endpoint accepts it
@@ -821,6 +874,8 @@ export { AbstractAuthorizationCodeService, type AbstractAuthorizationCodeService
821
874
  export type { DeviceAuthorizationServiceInterface } from "./services/device-authorization.ts";
822
875
  export type { UserServiceInterface } from "./services/user.ts";
823
876
  export type { AuthorizationCode, AuthorizeParameters, } from "../models/authorization-code.ts";
877
+ export type { AuthenticationRequest } from "../models/authentication.ts";
878
+ export { type AuthenticationOutcome, satisfiesAuthenticationRequest, } from "./authentication-request.ts";
824
879
  export type { DeviceAuthorization } from "../models/device-authorization.ts";
825
880
  export type { AuthorizationServerMetadata, DeviceAuthorizationResponse, ErrorResponse, OAuth2ErrorCode, } from "../models/responses.ts";
826
881
  export { challengeMethods, CODE_VERIFIER_MAX_LENGTH, CODE_VERIFIER_MIN_LENGTH, CODE_VERIFIER_PATTERN, generateCodeChallenge, generateCodeVerifier, generateState, getChallengeMethod, validateCodeChallenge, validateCodeVerifier, verifyCodeChallenge, } from "../utils/pkce.ts";
@@ -21,8 +21,9 @@
21
21
  * @module
22
22
  */
23
23
  import { snapshotAuthenticationContext } from "../utils/authentication-context.js";
24
- import { AccessDeniedError, InvalidRequestError, InvalidTokenError, isOAuth2Error, OAuth2Error, ServerError, toOAuth2Error, UnauthorizedClientError, UnsupportedGrantTypeError, UnsupportedResponseTypeError, } from "../errors.js";
24
+ import { AccessDeniedError, ConsentRequiredError, InvalidRequestError, InvalidTokenError, isOAuth2Error, LoginRequiredError, OAuth2Error, ServerError, toOAuth2Error, UnauthorizedClientError, UnsupportedGrantTypeError, UnsupportedResponseTypeError, } from "../errors.js";
25
25
  import { authenticateClientCredentials, extractClientCredentials, } from "./client-authentication.js";
26
+ import { assertSupportedValues, authenticationShortfall, DEFAULT_PROMPT_VALUES_SUPPORTED, parseAuthenticationRequest, } from "./authentication-request.js";
26
27
  import { isRedirectUriPattern, matchRedirectUri } from "./redirect-uri.js";
27
28
  import { AuthorizationCodeGrant } from "./grants/authorization-code.js";
28
29
  import { DeviceAuthorizationGrant } from "./grants/device-authorization.js";
@@ -134,6 +135,11 @@ export const ENDPOINT_PATHS = Object.fromEntries(ENDPOINT_ENTRIES.map(([key, { p
134
135
  * ```
135
136
  */
136
137
  export const ENDPOINT_METHODS = Object.fromEntries(ENDPOINT_ENTRIES.map(([key, { methods }]) => [key, methods]));
138
+ function authorizationResponseRedirect(target) {
139
+ if (target.issuer)
140
+ target.url.searchParams.set("iss", target.issuer);
141
+ return Response.redirect(target.url.toString(), 302);
142
+ }
137
143
  function isAuthorizationCodeGrant(grant) {
138
144
  return grant instanceof AuthorizationCodeGrant;
139
145
  }
@@ -189,6 +195,8 @@ export class AuthorizationServer extends ResourceServer {
189
195
  #endSession;
190
196
  #isPublicSuffix;
191
197
  #maxBodyBytes;
198
+ #promptValuesSupported;
199
+ #acrValuesSupported;
192
200
  #subjectOf;
193
201
  #userClaims;
194
202
  #introspectionClaims;
@@ -203,7 +211,8 @@ export class AuthorizationServer extends ResourceServer {
203
211
  * @throws {RangeError} If `maxBodyBytes` or `maxTokenBodyBytes` is not a
204
212
  * positive integer.
205
213
  * @throws {TypeError} If `realm` contains a character outside printable
206
- * ASCII.
214
+ * ASCII, or a `promptValuesSupported` or `acrValuesSupported` entry is
215
+ * empty or contains a space or non-ASCII character.
207
216
  */
208
217
  constructor(options) {
209
218
  super({
@@ -237,6 +246,10 @@ export class AuthorizationServer extends ResourceServer {
237
246
  this.#isPublicSuffix = options.isPublicSuffix;
238
247
  this.#maxBodyBytes = options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
239
248
  assertMaxBodyBytes(this.#maxBodyBytes, "maxBodyBytes");
249
+ this.#promptValuesSupported = assertSupportedValues("promptValuesSupported", options.promptValuesSupported ?? DEFAULT_PROMPT_VALUES_SUPPORTED);
250
+ if (options.acrValuesSupported) {
251
+ this.#acrValuesSupported = assertSupportedValues("acrValuesSupported", options.acrValuesSupported);
252
+ }
240
253
  this.#subjectOf = options.subjectOf ?? defaultSubjectOf;
241
254
  this.#userClaims = options.userClaims;
242
255
  this.#introspectionClaims = options.introspectionClaims;
@@ -461,7 +474,9 @@ export class AuthorizationServer extends ResourceServer {
461
474
  * `openid`, or `undefined` when the OIDC surface is off (no signing keys),
462
475
  * the token has no user, the scope lacks `openid`, or no issuer resolved.
463
476
  * The id_token's `aud` is the client id and it expires one hour after
464
- * issue.
477
+ * issue. Its `auth_time` and `acr` are the token's recorded
478
+ * `authenticationContext`, present exactly when the context has them,
479
+ * whatever `userClaims` returns.
465
480
  */
466
481
  async mintIdToken(token, context) {
467
482
  if (!this.signingKeys || !token.user || !context.issuer)
@@ -481,6 +496,15 @@ export class AuthorizationServer extends ResourceServer {
481
496
  claims.nonce = token.nonce;
482
497
  else
483
498
  delete claims.nonce;
499
+ const event = token.authenticationContext;
500
+ if (event?.auth_time !== undefined)
501
+ claims.auth_time = event.auth_time;
502
+ else
503
+ delete claims.auth_time;
504
+ if (event?.acr !== undefined)
505
+ claims.acr = event.acr;
506
+ else
507
+ delete claims.acr;
484
508
  return await signJwt(key, claims);
485
509
  }
486
510
  async #oidcClaims(user, scope, authenticationContext) {
@@ -742,6 +766,11 @@ export class AuthorizationServer extends ResourceServer {
742
766
  * responses from this endpoint, since there is no verified place to send the
743
767
  * user back to.
744
768
  *
769
+ * Every redirect to the client, the code and the error alike, carries `iss`
770
+ * set to the request's resolved issuer (RFC 9207), replacing any `iss` the
771
+ * registered `redirect_uri` itself carries. A request that resolves no
772
+ * `issuer` sends none.
773
+ *
745
774
  * Requires a grant extending {@linkcode AuthorizationCodeGrant} registered
746
775
  * under `authorization_code`; without one the endpoint answers 500
747
776
  * `server_error` (or rethrows, with `throwOnError`).
@@ -757,16 +786,17 @@ export class AuthorizationServer extends ResourceServer {
757
786
  return await this.#authorize(request, target, authenticateUser, handleConsent);
758
787
  }
759
788
  catch (error) {
760
- return this.#authorizeErrorResponse(error, target.url);
789
+ return this.#authorizeErrorResponse(error, target);
761
790
  }
762
791
  }
763
792
  async #authorize(request, target, authenticateUser, handleConsent) {
764
793
  const params = this.parseAuthorizeParameters(request);
765
794
  const grant = this.#authorizationCodeGrant();
766
- const { services } = await this.authorizationContext(request);
795
+ const { services, issuer } = await this.authorizationContext(request);
767
796
  const client = await this.#resolveAuthorizeClient(grant, params.clientId, services);
768
797
  const redirectUrl = this.#resolveRedirectTarget(client, params.redirectUri);
769
798
  target.url = redirectUrl;
799
+ target.issuer = issuer;
770
800
  if (!params.state) {
771
801
  throw new InvalidRequestError("state required");
772
802
  }
@@ -774,12 +804,21 @@ export class AuthorizationServer extends ResourceServer {
774
804
  this.#validateResponseType(params.responseType);
775
805
  const requestedScope = grant.parseScope(params.scope);
776
806
  this.#validateChallenge(grant, params);
777
- const authResult = await authenticateUser(request);
778
- if (authResult instanceof Response)
779
- return authResult;
807
+ const authentication = parseAuthenticationRequest(new URL(request.url).searchParams, this.#promptValuesSupported);
808
+ const silent = authentication.prompt.includes("none");
809
+ const authResult = await authenticateUser(request, authentication);
810
+ if (authResult instanceof Response) {
811
+ if (!silent)
812
+ return authResult;
813
+ await authResult.body?.cancel();
814
+ throw new LoginRequiredError("the user must sign in");
815
+ }
780
816
  if (!authResult) {
781
817
  throw new AccessDeniedError("authentication required");
782
818
  }
819
+ const shortfall = authenticationShortfall(authentication, authResult, Date.now());
820
+ if (shortfall)
821
+ throw new LoginRequiredError(shortfall);
783
822
  const { user, authorizedScope } = authResult;
784
823
  const authenticationContext = snapshotAuthenticationContext(authResult.authenticationContext);
785
824
  if (grant.requirePKCE && !params.challenge) {
@@ -793,6 +832,7 @@ export class AuthorizationServer extends ResourceServer {
793
832
  authorizedScope,
794
833
  services,
795
834
  handleConsent,
835
+ authentication,
796
836
  });
797
837
  if (consented instanceof Response)
798
838
  return consented;
@@ -807,9 +847,10 @@ export class AuthorizationServer extends ResourceServer {
807
847
  authenticationContext,
808
848
  }, request);
809
849
  redirectUrl.searchParams.set("code", authorizationCode.code);
810
- return Response.redirect(redirectUrl.toString(), 302);
850
+ return authorizationResponseRedirect({ url: redirectUrl, issuer });
811
851
  }
812
- #authorizeErrorResponse(error, redirectUrl) {
852
+ #authorizeErrorResponse(error, target) {
853
+ const redirectUrl = target.url;
813
854
  if (!redirectUrl || !(error instanceof Error) || !isOAuth2Error(error)) {
814
855
  return this.#handleEndpointError(error);
815
856
  }
@@ -824,7 +865,10 @@ export class AuthorizationServer extends ResourceServer {
824
865
  if (errorUri) {
825
866
  searchParams.set("error_uri", errorUri);
826
867
  }
827
- return Response.redirect(redirectUrl.toString(), 302);
868
+ return authorizationResponseRedirect({
869
+ url: redirectUrl,
870
+ issuer: target.issuer,
871
+ });
828
872
  }
829
873
  #authorizationCodeGrant() {
830
874
  const grant = this.grants[AUTHORIZATION_CODE_GRANT_TYPE];
@@ -894,14 +938,23 @@ export class AuthorizationServer extends ResourceServer {
894
938
  }
895
939
  }
896
940
  async #resolveScopeAndConsent(options) {
897
- const { grant, client, user, requestedScope, authorizedScope, services, handleConsent, } = options;
941
+ const { grant, client, user, requestedScope, authorizedScope, services, handleConsent, authentication, } = options;
898
942
  const acceptedScope = await grant.acceptedScope(client, user, requestedScope, services.tokenService);
899
943
  let scope = acceptedScope ?? undefined;
900
- const needsConsent = scope !== undefined && !(authorizedScope && authorizedScope.has(scope));
944
+ const forceConsent = authentication.prompt.includes("consent");
945
+ if (forceConsent && !handleConsent) {
946
+ throw new ConsentRequiredError("prompt=consent requires a consent handler");
947
+ }
948
+ const needsConsent = forceConsent ||
949
+ (scope !== undefined && !(authorizedScope && authorizedScope.has(scope)));
901
950
  if (needsConsent && handleConsent) {
902
- const consent = await handleConsent(client, scope, user);
903
- if (consent instanceof Response)
904
- return consent;
951
+ const consent = await handleConsent(client, scope, user, authentication);
952
+ if (consent instanceof Response) {
953
+ if (!authentication.prompt.includes("none"))
954
+ return consent;
955
+ await consent.body?.cancel();
956
+ throw new ConsentRequiredError("the user must consent");
957
+ }
905
958
  if (!consent.approved) {
906
959
  throw new AccessDeniedError("user denied consent");
907
960
  }
@@ -1136,7 +1189,9 @@ export class AuthorizationServer extends ResourceServer {
1136
1189
  * authorization code grant's own `challengeMethods`, so a server that
1137
1190
  * registers an extra method (or drops `S256`) advertises what it will
1138
1191
  * actually accept. It is omitted entirely when no authorization code grant
1139
- * is registered, since PKCE has nothing to apply to.
1192
+ * is registered, since PKCE has nothing to apply to. The same condition
1193
+ * governs `authorization_response_iss_parameter_supported: true`
1194
+ * (RFC 9207 §3): the authorization endpoint's redirects carry `iss`.
1140
1195
  *
1141
1196
  * `token_endpoint_auth_methods_supported` always includes `none`, the
1142
1197
  * RFC 7591 method for a client with no secret. The token endpoint accepts it
@@ -1178,6 +1233,10 @@ export class AuthorizationServer extends ResourceServer {
1178
1233
  metadata.code_challenge_methods_supported = challengeMethods;
1179
1234
  }
1180
1235
  metadata.response_types_supported = hasAuthCodeGrant ? ["code"] : [];
1236
+ if (hasAuthCodeGrant) {
1237
+ metadata.authorization_response_iss_parameter_supported = true;
1238
+ metadata.prompt_values_supported = [...this.#promptValuesSupported];
1239
+ }
1181
1240
  const scopesSupported = context.scopesSupported ?? this.scopesSupported;
1182
1241
  if (scopesSupported) {
1183
1242
  metadata.scopes_supported = scopesSupported;
@@ -1186,6 +1245,9 @@ export class AuthorizationServer extends ResourceServer {
1186
1245
  this.#advertiseEndpoints(metadata, endpoints, true);
1187
1246
  metadata.id_token_signing_alg_values_supported = ["ES256"];
1188
1247
  metadata.subject_types_supported = ["public"];
1248
+ if (hasAuthCodeGrant && this.#acrValuesSupported?.length) {
1249
+ metadata.acr_values_supported = [...this.#acrValuesSupported];
1250
+ }
1189
1251
  }
1190
1252
  return metadata;
1191
1253
  }
@@ -1384,6 +1446,7 @@ export { PasswordGrant } from "./grants/password.js";
1384
1446
  export { DeviceAuthorizationGrant } from "./grants/device-authorization.js";
1385
1447
  export { AbstractTokenService, } from "./services/token.js";
1386
1448
  export { AbstractAuthorizationCodeService, } from "./services/authorization-code.js";
1449
+ export { satisfiesAuthenticationRequest, } from "./authentication-request.js";
1387
1450
  export { challengeMethods, CODE_VERIFIER_MAX_LENGTH, CODE_VERIFIER_MIN_LENGTH, CODE_VERIFIER_PATTERN, generateCodeChallenge, generateCodeVerifier, generateState, getChallengeMethod, validateCodeChallenge, validateCodeVerifier, verifyCodeChallenge, } from "../utils/pkce.js";
1388
1451
  export { encodeBasicAuth, parseBasicAuth, tryParseBasicAuth, } from "../utils/basic-auth.js";
1389
1452
  export { checkRedirectUriPattern, isRedirectUriPattern, matchRedirectUri, } from "./redirect-uri.js";
@@ -9,14 +9,15 @@
9
9
  * @module
10
10
  */
11
11
  export type { ClientCredentials, ClientInterface } from "../models/client.ts";
12
- export type { AuthenticationContext } from "../models/authentication.ts";
12
+ export type { AuthenticationContext, AuthenticationRequest, } from "../models/authentication.ts";
13
13
  export type { IntrospectionResponse, RefreshToken, Token, TokenResponse, } from "../models/token.ts";
14
14
  export { AbstractScope, BasicScope } from "../models/scope.ts";
15
15
  export type { ScopeConstructor } from "../models/scope.ts";
16
16
  export { Authorization, authorizationFromClaims, } from "../models/authorization.ts";
17
17
  export type { AuthorizationFailure, AuthorizationInit, OrganizationContext, RequireConditions, } from "../models/authorization.ts";
18
- export { AccessDeniedError, AuthorizationPendingError, ExpiredTokenError, InsufficientPermissionsError, InsufficientScopeError, InvalidClientError, InvalidGrantError, InvalidRequestError, InvalidScopeError, InvalidTokenError, isOAuth2Error, OAuth2Error, ServerError, SlowDownError, TemporarilyUnavailableError, toOAuth2Error, UnauthorizedClientError, UnsupportedGrantTypeError, UnsupportedResponseTypeError, UnsupportedTokenTypeError, } from "../errors.ts";
18
+ export { AccessDeniedError, AccountSelectionRequiredError, AuthorizationPendingError, ConsentRequiredError, ExpiredTokenError, InsufficientPermissionsError, InsufficientScopeError, InteractionRequiredError, InvalidClientError, InvalidGrantError, InvalidRequestError, InvalidScopeError, InvalidTokenError, isOAuth2Error, LoginRequiredError, OAuth2Error, ServerError, SlowDownError, TemporarilyUnavailableError, toOAuth2Error, UnauthorizedClientError, UnsupportedGrantTypeError, UnsupportedResponseTypeError, UnsupportedTokenTypeError, } from "../errors.ts";
19
19
  export type { OAuth2ErrorClass, OAuth2ProblemDetailsExtensions, } from "../errors.ts";
20
+ export { type AuthenticationOutcome, satisfiesAuthenticationRequest, } from "./authentication-request.ts";
20
21
  export type { TokenReaderInterface } from "./services/token.ts";
21
22
  export { checkRedirectUriPattern, isRedirectUriPattern, matchRedirectUri, } from "./redirect-uri.ts";
22
23
  export type { IsPublicSuffix, RedirectUriPatternRule, RedirectUriPatternViolation, } from "./redirect-uri.ts";
@@ -10,5 +10,6 @@
10
10
  */
11
11
  export { AbstractScope, BasicScope } from "../models/scope.js";
12
12
  export { Authorization, authorizationFromClaims, } from "../models/authorization.js";
13
- export { AccessDeniedError, AuthorizationPendingError, ExpiredTokenError, InsufficientPermissionsError, InsufficientScopeError, InvalidClientError, InvalidGrantError, InvalidRequestError, InvalidScopeError, InvalidTokenError, isOAuth2Error, OAuth2Error, ServerError, SlowDownError, TemporarilyUnavailableError, toOAuth2Error, UnauthorizedClientError, UnsupportedGrantTypeError, UnsupportedResponseTypeError, UnsupportedTokenTypeError, } from "../errors.js";
13
+ export { AccessDeniedError, AccountSelectionRequiredError, AuthorizationPendingError, ConsentRequiredError, ExpiredTokenError, InsufficientPermissionsError, InsufficientScopeError, InteractionRequiredError, InvalidClientError, InvalidGrantError, InvalidRequestError, InvalidScopeError, InvalidTokenError, isOAuth2Error, LoginRequiredError, OAuth2Error, ServerError, SlowDownError, TemporarilyUnavailableError, toOAuth2Error, UnauthorizedClientError, UnsupportedGrantTypeError, UnsupportedResponseTypeError, UnsupportedTokenTypeError, } from "../errors.js";
14
+ export { satisfiesAuthenticationRequest, } from "./authentication-request.js";
14
15
  export { checkRedirectUriPattern, isRedirectUriPattern, matchRedirectUri, } from "./redirect-uri.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@udibo/oauth2",
3
- "version": "0.25.0",
3
+ "version": "0.27.0",
4
4
  "description": "A flexible OAuth2 toolkit: framework-agnostic authorization & resource servers, a typed client, Hono adapters (including a backend-for-frontend), and React bindings.",
5
5
  "keywords": [
6
6
  "authorization-server",