@udibo/oauth2 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/SECURITY.md +0 -4
- package/esm/adapters/hono/_common.d.ts +10 -13
- package/esm/adapters/hono/_common.js +11 -20
- package/esm/adapters/hono/authorization-server.d.ts +16 -10
- package/esm/adapters/hono/authorization-server.js +13 -8
- package/esm/adapters/hono/bff/auth-request-store.d.ts +4 -0
- package/esm/adapters/hono/bff/auth-request-store.js +4 -0
- package/esm/adapters/hono/bff/bff.d.ts +29 -18
- package/esm/adapters/hono/bff/bff.js +15 -11
- package/esm/adapters/hono/bff/proxy.js +7 -55
- package/esm/adapters/hono/bff/session-store.d.ts +9 -9
- package/esm/adapters/hono/bff/session-store.js +3 -2
- package/esm/adapters/hono/bff/testing.d.ts +14 -3
- package/esm/adapters/hono/bff/testing.js +14 -3
- package/esm/adapters/hono/identity.d.ts +5 -3
- package/esm/adapters/hono/identity.js +1 -17
- package/esm/adapters/hono/resource-server.d.ts +3 -2
- package/esm/adapters/hono/resource-server.js +3 -2
- package/esm/client/_http.d.ts +4 -7
- package/esm/client/_http.js +4 -37
- package/esm/client/base.d.ts +3 -6
- package/esm/client/bff-client.d.ts +7 -6
- package/esm/client/bff-client.js +7 -6
- package/esm/client/browser-storage.d.ts +33 -34
- package/esm/client/browser-storage.js +47 -32
- package/esm/client/check.d.ts +10 -3
- package/esm/client/check.js +28 -8
- package/esm/client/direct-client.d.ts +49 -29
- package/esm/client/direct-client.js +59 -59
- package/esm/client/discovery-cache.d.ts +12 -5
- package/esm/client/discovery-cache.js +11 -4
- package/esm/client/events.d.ts +11 -3
- package/esm/client/events.js +1 -1
- package/esm/client/mod.d.ts +6 -4
- package/esm/client/mod.js +5 -3
- package/esm/client/storage.d.ts +53 -23
- package/esm/client/storage.js +43 -15
- package/esm/errors.d.ts +15 -12
- package/esm/errors.js +12 -8
- package/esm/identity/delivery.d.ts +7 -7
- package/esm/identity/delivery.js +1 -2
- package/esm/identity/errors.d.ts +10 -4
- package/esm/identity/errors.js +4 -1
- package/esm/identity/events.d.ts +21 -5
- package/esm/identity/events.js +4 -2
- package/esm/identity/external/_shared.d.ts +5 -7
- package/esm/identity/external/_shared.js +5 -7
- package/esm/identity/external/_token-exchange.d.ts +3 -6
- package/esm/identity/external/_token-exchange.js +2 -5
- package/esm/identity/external/apple-client-secret.d.ts +13 -8
- package/esm/identity/external/apple-client-secret.js +9 -6
- package/esm/identity/external/apple.d.ts +17 -10
- package/esm/identity/external/apple.js +12 -9
- package/esm/identity/external/discord.d.ts +5 -1
- package/esm/identity/external/errors.d.ts +6 -2
- package/esm/identity/external/errors.js +6 -2
- package/esm/identity/external/flow.d.ts +9 -6
- package/esm/identity/external/flow.js +6 -5
- package/esm/identity/external/github.d.ts +7 -3
- package/esm/identity/external/github.js +2 -2
- package/esm/identity/external/google.d.ts +5 -1
- package/esm/identity/external/oauth2.d.ts +13 -2
- package/esm/identity/external/oauth2.js +3 -3
- package/esm/identity/external/oidc.d.ts +21 -10
- package/esm/identity/external/oidc.js +11 -6
- package/esm/identity/external/provider.d.ts +4 -2
- package/esm/identity/identifier.d.ts +6 -5
- package/esm/identity/identifier.js +6 -5
- package/esm/identity/lockout.d.ts +4 -3
- package/esm/identity/lockout.js +4 -3
- package/esm/identity/mfa/mod.d.ts +2 -1
- package/esm/identity/mfa/mod.js +2 -1
- package/esm/identity/mfa/recovery-codes.d.ts +2 -1
- package/esm/identity/mfa/service.d.ts +29 -11
- package/esm/identity/mfa/service.js +35 -11
- package/esm/identity/mfa/totp.d.ts +4 -2
- package/esm/identity/mfa/totp.js +4 -2
- package/esm/identity/migration.d.ts +8 -7
- package/esm/identity/migration.js +9 -12
- package/esm/identity/mod.d.ts +2 -2
- package/esm/identity/mod.js +2 -2
- package/esm/identity/otp.d.ts +23 -16
- package/esm/identity/otp.js +13 -12
- package/esm/identity/password-policy.d.ts +3 -3
- package/esm/identity/password-policy.js +3 -3
- package/esm/identity/password.d.ts +23 -20
- package/esm/identity/password.js +15 -16
- package/esm/identity/rate-limit.d.ts +1 -7
- package/esm/identity/rate-limit.js +1 -2
- package/esm/identity/service.d.ts +76 -44
- package/esm/identity/service.js +86 -60
- package/esm/identity/session.d.ts +5 -4
- package/esm/identity/session.js +5 -4
- package/esm/identity/token-flow.d.ts +8 -8
- package/esm/identity/token-flow.js +5 -6
- package/esm/models/client.d.ts +7 -4
- package/esm/models/token.d.ts +2 -3
- package/esm/react/callback.d.ts +3 -3
- package/esm/react/callback.js +3 -3
- package/esm/react/components/class-names.d.ts +3 -6
- package/esm/react/components/class-names.js +3 -6
- package/esm/react/components/internal.d.ts +7 -17
- package/esm/react/components/internal.js +7 -17
- package/esm/react/components/mod.d.ts +7 -5
- package/esm/react/components/mod.js +7 -5
- package/esm/react/components/types.d.ts +8 -6
- package/esm/react/context.d.ts +3 -3
- package/esm/react/provider.d.ts +3 -2
- package/esm/react/provider.js +0 -13
- package/esm/react/require-auth.d.ts +0 -3
- package/esm/react/require-auth.js +0 -3
- package/esm/react/testing.d.ts +3 -2
- package/esm/react/testing.js +3 -3
- package/esm/react/use-oauth2.d.ts +1 -1
- package/esm/server/authorization-server.d.ts +81 -54
- package/esm/server/authorization-server.js +76 -100
- package/esm/server/grants/authorization-code.d.ts +7 -3
- package/esm/server/grants/authorization-code.js +6 -2
- package/esm/server/grants/device-authorization.d.ts +1 -1
- package/esm/server/grants/grant.d.ts +15 -8
- package/esm/server/grants/grant.js +26 -18
- package/esm/server/grants/password.d.ts +1 -1
- package/esm/server/grants/refresh-token.d.ts +6 -3
- package/esm/server/grants/refresh-token.js +4 -3
- package/esm/server/introspection-token-reader.d.ts +16 -7
- package/esm/server/introspection-token-reader.js +9 -3
- package/esm/server/jwks-token-reader.d.ts +3 -3
- package/esm/server/jwks-token-reader.js +3 -3
- package/esm/server/public-suffix/rules.d.ts +4 -4
- package/esm/server/public-suffix/rules.js +4 -4
- package/esm/server/redirect-uri.d.ts +6 -9
- package/esm/server/redirect-uri.js +7 -34
- package/esm/server/resource-server.d.ts +5 -3
- package/esm/server/resource-server.js +5 -3
- package/esm/server/services/client.d.ts +5 -1
- package/esm/server/services/device-authorization.d.ts +6 -6
- package/esm/server/services/token.d.ts +15 -8
- package/esm/server/services/token.js +1 -1
- package/esm/server/signing-keys.d.ts +24 -9
- package/esm/server/signing-keys.js +20 -9
- package/esm/testing/contract/mod.d.ts +3 -3
- package/esm/testing/contract/mod.js +3 -3
- package/esm/testing/mod.d.ts +4 -2
- package/esm/testing/mod.js +4 -2
- package/esm/testing/services.d.ts +1 -1
- package/esm/testing/services.js +1 -1
- package/esm/testing/tenant.d.ts +13 -4
- package/esm/utils/_buffer.d.ts +3 -2
- package/esm/utils/_buffer.js +3 -2
- package/esm/utils/_timing-safe.d.ts +8 -6
- package/esm/utils/_timing-safe.js +8 -6
- package/esm/utils/basic-auth.d.ts +5 -12
- package/esm/utils/basic-auth.js +5 -12
- package/esm/utils/crypto.d.ts +2 -1
- package/esm/utils/crypto.js +2 -1
- package/esm/utils/text.d.ts +2 -9
- package/esm/utils/text.js +2 -9
- package/esm/utils/url.d.ts +2 -2
- package/esm/utils/url.js +0 -2
- package/package.json +1 -1
package/esm/models/client.d.ts
CHANGED
|
@@ -33,7 +33,9 @@ export interface ClientInterface {
|
|
|
33
33
|
* the request when none authorizes it.
|
|
34
34
|
*
|
|
35
35
|
* An ordinary entry is a **literal**, compared by exact string match (RFC
|
|
36
|
-
* 6749 §3.1.2.3), and an exact match always wins.
|
|
36
|
+
* 6749 §3.1.2.3), and an exact match always wins. A literal on a loopback
|
|
37
|
+
* IP host (`127.0.0.1` or `[::1]`) also matches the same URI on any port,
|
|
38
|
+
* for native apps (RFC 8252 §7.3). An entry may instead be a
|
|
37
39
|
* **pattern** — one `*` in the leftmost host label, `https` only, over a
|
|
38
40
|
* single registrable domain (`https://myapp-*.myorg.deno.net/cb`) — so one
|
|
39
41
|
* registration covers the per-deploy hostnames a preview environment
|
|
@@ -48,9 +50,10 @@ export interface ClientInterface {
|
|
|
48
50
|
* **literal** entry, so order the array with that default first. When omitted
|
|
49
51
|
* or empty, no redirect URI is authorized at all.
|
|
50
52
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
53
|
+
* Any entry containing a `*` is read as a pattern, so a literal URI that
|
|
54
|
+
* happens to contain one matches **nothing** unless it also satisfies the
|
|
55
|
+
* pattern rules. That fails closed, but silently: register such a URI in a
|
|
56
|
+
* form without `*`.
|
|
54
57
|
*/
|
|
55
58
|
redirectUris?: string[];
|
|
56
59
|
/**
|
package/esm/models/token.d.ts
CHANGED
|
@@ -62,9 +62,8 @@ export interface RefreshToken<Client extends ClientInterface, User, Scope extend
|
|
|
62
62
|
* service that persists refresh tokens **must** persist and restore it —
|
|
63
63
|
* dropping it on the round trip disables the cap.
|
|
64
64
|
*
|
|
65
|
-
* A record without an anchor
|
|
66
|
-
*
|
|
67
|
-
* is capped from then on.
|
|
65
|
+
* A record without an anchor rotates once uncapped; that rotation is issued
|
|
66
|
+
* with a fresh anchor, so the family is capped from then on.
|
|
68
67
|
*/
|
|
69
68
|
familyCreatedAt?: Date;
|
|
70
69
|
}
|
package/esm/react/callback.d.ts
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* component renders its `fallback` with a clear error rather than pretend
|
|
8
8
|
* otherwise.
|
|
9
9
|
*
|
|
10
|
-
* Idempotent against React
|
|
11
|
-
*
|
|
12
|
-
* first call's promise.
|
|
10
|
+
* Idempotent against React strict-mode double-mounts because the client
|
|
11
|
+
* dedupes by `code`: a second call while the first exchange is still in
|
|
12
|
+
* flight returns the first call's promise.
|
|
13
13
|
*
|
|
14
14
|
* @module
|
|
15
15
|
*/
|
package/esm/react/callback.js
CHANGED
|
@@ -9,9 +9,9 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
9
9
|
* component renders its `fallback` with a clear error rather than pretend
|
|
10
10
|
* otherwise.
|
|
11
11
|
*
|
|
12
|
-
* Idempotent against React
|
|
13
|
-
*
|
|
14
|
-
* first call's promise.
|
|
12
|
+
* Idempotent against React strict-mode double-mounts because the client
|
|
13
|
+
* dedupes by `code`: a second call while the first exchange is still in
|
|
14
|
+
* flight returns the first call's promise.
|
|
15
15
|
*
|
|
16
16
|
* @module
|
|
17
17
|
*/
|
|
@@ -18,8 +18,7 @@ import type { AuthFormClassNames } from "./types.js";
|
|
|
18
18
|
* {@link AuthFormClassNamesProvider}'s map with `overrides` applied slot by
|
|
19
19
|
* slot. An absent or `undefined` slot in `overrides` keeps the inherited value,
|
|
20
20
|
* and with no provider above the map is empty (every slot `undefined`), so the
|
|
21
|
-
* hook is safe to call anywhere.
|
|
22
|
-
* implemented.
|
|
21
|
+
* hook is safe to call anywhere.
|
|
23
22
|
*
|
|
24
23
|
* The result is cached on the slot values, so passing a fresh `overrides`
|
|
25
24
|
* literal every render returns the identical map.
|
|
@@ -48,10 +47,8 @@ import type { AuthFormClassNames } from "./types.js";
|
|
|
48
47
|
*/
|
|
49
48
|
export declare function useAuthFormClassNames(overrides?: AuthFormClassNames): Readonly<AuthFormClassNames>;
|
|
50
49
|
/**
|
|
51
|
-
* Publishes an already-resolved map
|
|
52
|
-
*
|
|
53
|
-
* publish through this, so the precedence rule keeps exactly one
|
|
54
|
-
* implementation. App code wants {@link AuthFormClassNamesProvider}.
|
|
50
|
+
* Publishes an already-resolved map (from {@link useAuthFormClassNames})
|
|
51
|
+
* verbatim, without merging. App code wants {@link AuthFormClassNamesProvider}.
|
|
55
52
|
*/
|
|
56
53
|
export declare function AuthFormClassNamesScope(props: {
|
|
57
54
|
classNames: Readonly<AuthFormClassNames>;
|
|
@@ -35,8 +35,7 @@ function slotKey(classNames) {
|
|
|
35
35
|
* {@link AuthFormClassNamesProvider}'s map with `overrides` applied slot by
|
|
36
36
|
* slot. An absent or `undefined` slot in `overrides` keeps the inherited value,
|
|
37
37
|
* and with no provider above the map is empty (every slot `undefined`), so the
|
|
38
|
-
* hook is safe to call anywhere.
|
|
39
|
-
* implemented.
|
|
38
|
+
* hook is safe to call anywhere.
|
|
40
39
|
*
|
|
41
40
|
* The result is cached on the slot values, so passing a fresh `overrides`
|
|
42
41
|
* literal every render returns the identical map.
|
|
@@ -78,10 +77,8 @@ export function useAuthFormClassNames(overrides) {
|
|
|
78
77
|
return held.current.resolved;
|
|
79
78
|
}
|
|
80
79
|
/**
|
|
81
|
-
* Publishes an already-resolved map
|
|
82
|
-
*
|
|
83
|
-
* publish through this, so the precedence rule keeps exactly one
|
|
84
|
-
* implementation. App code wants {@link AuthFormClassNamesProvider}.
|
|
80
|
+
* Publishes an already-resolved map (from {@link useAuthFormClassNames})
|
|
81
|
+
* verbatim, without merging. App code wants {@link AuthFormClassNamesProvider}.
|
|
85
82
|
*/
|
|
86
83
|
export function AuthFormClassNamesScope(props) {
|
|
87
84
|
const { classNames, children } = props;
|
|
@@ -2,17 +2,10 @@ import { type ReactNode, type Ref } from "react";
|
|
|
2
2
|
import type { AuthFieldProps, AuthFormState } from "./use-auth-form.js";
|
|
3
3
|
import type { AuthFormClassNames, AuthFormValues, SocialProvidersProps } from "./types.js";
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* carrying `data-oauth2-form={name}`, then the `<form>` with its error summary
|
|
10
|
-
* and the caller's fields. Use `aboveForm` for content that belongs inside the
|
|
11
|
-
* root but outside the form (social buttons, an enrollment secret), and
|
|
12
|
-
* `succeeded` for a terminal state that replaces the form entirely. With a
|
|
13
|
-
* `render` — the form's render-prop `children` — that markup is skipped for the
|
|
14
|
-
* caller's own. Either way the already-resolved `classNames` is published to
|
|
15
|
-
* what renders, so the elements inside take their classes from the tree.
|
|
5
|
+
* What every default form component returns: the shared root, `<form>` and
|
|
6
|
+
* error summary, or the caller's `render` output instead, with the resolved
|
|
7
|
+
* `classNames` published to either. `aboveForm` sits inside the root but
|
|
8
|
+
* outside the form; `succeeded` replaces the form.
|
|
16
9
|
*/
|
|
17
10
|
export declare function AuthFormShell<V extends AuthFormValues>(props: {
|
|
18
11
|
name: string;
|
|
@@ -48,12 +41,9 @@ export declare function ErrorSummary(props: {
|
|
|
48
41
|
focusTrigger?: number;
|
|
49
42
|
}): ReactNode;
|
|
50
43
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* the submit button. No-ops on the initial render and when the form
|
|
55
|
-
* carries a form-level error ({@link ErrorSummary} owns that focus). Call it
|
|
56
|
-
* once, unconditionally, from a form component built on {@link useAuthForm}.
|
|
44
|
+
* After a failed submit, focuses the first field with an error; does nothing
|
|
45
|
+
* when there is a form-level error, which {@link ErrorSummary} focuses. Call
|
|
46
|
+
* once, unconditionally, from a form built on {@link useAuthForm}.
|
|
57
47
|
*/
|
|
58
48
|
export declare function useFocusFirstError<V extends AuthFormValues>(form: AuthFormState<V>): void;
|
|
59
49
|
export declare function SocialButtons(props: SocialProvidersProps): ReactNode;
|
|
@@ -2,17 +2,10 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { useEffect, useRef, } from "react";
|
|
3
3
|
import { AuthFormClassNamesScope, useAuthFormClassNames, } from "./class-names.js";
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* carrying `data-oauth2-form={name}`, then the `<form>` with its error summary
|
|
10
|
-
* and the caller's fields. Use `aboveForm` for content that belongs inside the
|
|
11
|
-
* root but outside the form (social buttons, an enrollment secret), and
|
|
12
|
-
* `succeeded` for a terminal state that replaces the form entirely. With a
|
|
13
|
-
* `render` — the form's render-prop `children` — that markup is skipped for the
|
|
14
|
-
* caller's own. Either way the already-resolved `classNames` is published to
|
|
15
|
-
* what renders, so the elements inside take their classes from the tree.
|
|
5
|
+
* What every default form component returns: the shared root, `<form>` and
|
|
6
|
+
* error summary, or the caller's `render` output instead, with the resolved
|
|
7
|
+
* `classNames` published to either. `aboveForm` sits inside the root but
|
|
8
|
+
* outside the form; `succeeded` replaces the form.
|
|
16
9
|
*/
|
|
17
10
|
export function AuthFormShell(props) {
|
|
18
11
|
const { name, form, className, classNames, render, rootProps, aboveForm, succeeded, children, action, method, formRef, } = props;
|
|
@@ -46,12 +39,9 @@ export function ErrorSummary(props) {
|
|
|
46
39
|
return (_jsx("div", { ref: ref, tabIndex: -1, "data-oauth2-error-summary": "", className: classNames.errorSummary, children: _jsx("span", { role: "alert", "data-oauth2-error-summary-message": "", children: error }) }));
|
|
47
40
|
}
|
|
48
41
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* the submit button. No-ops on the initial render and when the form
|
|
53
|
-
* carries a form-level error ({@link ErrorSummary} owns that focus). Call it
|
|
54
|
-
* once, unconditionally, from a form component built on {@link useAuthForm}.
|
|
42
|
+
* After a failed submit, focuses the first field with an error; does nothing
|
|
43
|
+
* when there is a form-level error, which {@link ErrorSummary} focuses. Call
|
|
44
|
+
* once, unconditionally, from a form built on {@link useAuthForm}.
|
|
55
45
|
*/
|
|
56
46
|
export function useFocusFirstError(form) {
|
|
57
47
|
const handled = useRef(0);
|
|
@@ -27,9 +27,12 @@
|
|
|
27
27
|
* ## Server-rendered pages
|
|
28
28
|
*
|
|
29
29
|
* Pass `action` + `method` and the rendered `<form>` carries them, so a
|
|
30
|
-
* server-rendered page still posts when JavaScript never arrives — every
|
|
31
|
-
* carries its `name`, so the native post sends
|
|
32
|
-
*
|
|
30
|
+
* server-rendered page still posts when JavaScript never arrives — every
|
|
31
|
+
* rendered field carries its `name`, so the native post sends those fields
|
|
32
|
+
* under the keys `onSubmit` receives. Values a form holds without rendering a
|
|
33
|
+
* field for them are absent from a native post: `ResetPasswordForm`'s
|
|
34
|
+
* `token`, `MfaChallengeForm`'s `method`, and any `SignUpForm` field left
|
|
35
|
+
* hidden. Once React is running, `onSubmit` handles the submit and the
|
|
33
36
|
* native post is suppressed. `formRef` hands you the same `<form>` element, for
|
|
34
37
|
* example to trigger a native `submit()` yourself.
|
|
35
38
|
*
|
|
@@ -56,8 +59,7 @@
|
|
|
56
59
|
* - One-time-code fields use `autocomplete="one-time-code"` and **never block
|
|
57
60
|
* paste** (WCAG 2.2 §3.3.8 Accessible Authentication).
|
|
58
61
|
* - Section titles carry heading semantics; the components ship unstyled, so
|
|
59
|
-
* **contrast and visible focus are yours to satisfy** with your own theme
|
|
60
|
-
* the ratios and focus rules Udibo uses are in its `DESIGN.md`.
|
|
62
|
+
* **contrast and visible focus are yours to satisfy** with your own theme.
|
|
61
63
|
*
|
|
62
64
|
* @example Plain React Router v7
|
|
63
65
|
* ```tsx
|
|
@@ -27,9 +27,12 @@
|
|
|
27
27
|
* ## Server-rendered pages
|
|
28
28
|
*
|
|
29
29
|
* Pass `action` + `method` and the rendered `<form>` carries them, so a
|
|
30
|
-
* server-rendered page still posts when JavaScript never arrives — every
|
|
31
|
-
* carries its `name`, so the native post sends
|
|
32
|
-
*
|
|
30
|
+
* server-rendered page still posts when JavaScript never arrives — every
|
|
31
|
+
* rendered field carries its `name`, so the native post sends those fields
|
|
32
|
+
* under the keys `onSubmit` receives. Values a form holds without rendering a
|
|
33
|
+
* field for them are absent from a native post: `ResetPasswordForm`'s
|
|
34
|
+
* `token`, `MfaChallengeForm`'s `method`, and any `SignUpForm` field left
|
|
35
|
+
* hidden. Once React is running, `onSubmit` handles the submit and the
|
|
33
36
|
* native post is suppressed. `formRef` hands you the same `<form>` element, for
|
|
34
37
|
* example to trigger a native `submit()` yourself.
|
|
35
38
|
*
|
|
@@ -56,8 +59,7 @@
|
|
|
56
59
|
* - One-time-code fields use `autocomplete="one-time-code"` and **never block
|
|
57
60
|
* paste** (WCAG 2.2 §3.3.8 Accessible Authentication).
|
|
58
61
|
* - Section titles carry heading semantics; the components ship unstyled, so
|
|
59
|
-
* **contrast and visible focus are yours to satisfy** with your own theme
|
|
60
|
-
* the ratios and focus rules Udibo uses are in its `DESIGN.md`.
|
|
62
|
+
* **contrast and visible focus are yours to satisfy** with your own theme.
|
|
61
63
|
*
|
|
62
64
|
* @example Plain React Router v7
|
|
63
65
|
* ```tsx
|
|
@@ -107,7 +107,7 @@ export interface AuthFormClassNames extends BaseClassNames {
|
|
|
107
107
|
/** Each inline field error (`data-oauth2-error`). */
|
|
108
108
|
error?: string;
|
|
109
109
|
/**
|
|
110
|
-
* Inline content rendered under a field —
|
|
110
|
+
* Inline content rendered under a field — the sign-in form's "Forgot
|
|
111
111
|
* password?" link (`data-oauth2-forgot-password`).
|
|
112
112
|
*/
|
|
113
113
|
hint?: string;
|
|
@@ -186,17 +186,19 @@ export interface BaseAuthFormProps<V extends AuthFormValues> {
|
|
|
186
186
|
/**
|
|
187
187
|
* `action` for the rendered `<form>`. Set it (with {@link method}) on a
|
|
188
188
|
* server-rendered page so the form still posts when JavaScript never
|
|
189
|
-
* arrives; every field carries its `name`, so a native post sends
|
|
190
|
-
* keys `onSubmit` receives.
|
|
191
|
-
*
|
|
189
|
+
* arrives; every rendered field carries its `name`, so a native post sends
|
|
190
|
+
* those fields under the keys `onSubmit` receives. A value the form holds
|
|
191
|
+
* without a rendered field (such as `ResetPasswordForm`'s `token`) is not
|
|
192
|
+
* posted, so the server's handler must obtain it another way. Once React is
|
|
193
|
+
* running, `onSubmit` handles the submit and the native post is suppressed.
|
|
192
194
|
*
|
|
193
195
|
* Ignored in render-prop mode — you own the `<form>` there.
|
|
194
196
|
*/
|
|
195
197
|
action?: string;
|
|
196
198
|
/**
|
|
197
199
|
* `method` for the rendered `<form>`. Defaults to `"post"` whenever
|
|
198
|
-
* {@link action} is set, because the fields these forms render — passwords
|
|
199
|
-
* one-time codes
|
|
200
|
+
* {@link action} is set, because the fields these forms render — passwords
|
|
201
|
+
* and one-time codes — must never reach a URL, where a `get` form
|
|
200
202
|
* would put them: browser history, the `Referer` sent to every third-party
|
|
201
203
|
* asset on the destination page, and the server's access log.
|
|
202
204
|
*/
|
package/esm/react/context.d.ts
CHANGED
|
@@ -14,9 +14,9 @@ export interface OAuth2State {
|
|
|
14
14
|
/** Whether a user is currently authenticated. */
|
|
15
15
|
isAuthenticated: boolean;
|
|
16
16
|
/**
|
|
17
|
-
* `true`
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* `true` while the provider's initial session probe is in flight; `false`
|
|
18
|
+
* once it settles, and from the start when the provider is given
|
|
19
|
+
* `initialState`. A later token refresh does not set it.
|
|
20
20
|
*/
|
|
21
21
|
isLoading: boolean;
|
|
22
22
|
/**
|
package/esm/react/provider.d.ts
CHANGED
|
@@ -19,8 +19,9 @@ export interface OAuth2ProviderProps {
|
|
|
19
19
|
* Optional pre-resolved auth state (typically from a server-side
|
|
20
20
|
* session probe). Populating this skips the on-mount session probe
|
|
21
21
|
* and renders the authenticated tree on the first paint — no
|
|
22
|
-
* hydration flash.
|
|
23
|
-
*
|
|
22
|
+
* hydration flash. When a later render passes a different value, the
|
|
23
|
+
* provider re-seeds its state only if `isAuthenticated` or `user.sub`
|
|
24
|
+
* changed, so an object built inline in render is fine.
|
|
24
25
|
*/
|
|
25
26
|
initialState?: Partial<OAuth2State>;
|
|
26
27
|
/** The app subtree that reads auth state via `useOAuth2()`. */
|
package/esm/react/provider.js
CHANGED
|
@@ -19,24 +19,12 @@ const DEFAULT_STATE = {
|
|
|
19
19
|
};
|
|
20
20
|
const RENEW_SKEW_SECONDS = 30;
|
|
21
21
|
const MIN_RENEW_MS = 5_000;
|
|
22
|
-
/**
|
|
23
|
-
* Fraction of the renew delay given up to jitter, applied one-sided so a renew
|
|
24
|
-
* never lands later than the un-jittered schedule.
|
|
25
|
-
*/
|
|
26
22
|
const RENEW_JITTER = 0.1;
|
|
27
23
|
const isBrowser = () => typeof window !== "undefined";
|
|
28
|
-
/**
|
|
29
|
-
* Delay before renewing a session that expires in `expiresIn` seconds.
|
|
30
|
-
*
|
|
31
|
-
* Floors at {@link MIN_RENEW_MS}, so `0` — which a `DirectClient` reports for
|
|
32
|
-
* an already-expired token a refresh token can still revive — schedules a
|
|
33
|
-
* near-immediate renew rather than nothing at all.
|
|
34
|
-
*/
|
|
35
24
|
function renewDelayMs(expiresIn) {
|
|
36
25
|
const base = Math.max(MIN_RENEW_MS, (expiresIn - RENEW_SKEW_SECONDS) * 1000);
|
|
37
26
|
return base * (1 - RENEW_JITTER * Math.random());
|
|
38
27
|
}
|
|
39
|
-
/** Seconds until `tokens` expires, or `null` when the server said nothing. */
|
|
40
28
|
function expiresInFrom(tokens) {
|
|
41
29
|
if (!tokens.accessTokenExpiresAt)
|
|
42
30
|
return null;
|
|
@@ -65,7 +53,6 @@ export function OAuth2Provider(props) {
|
|
|
65
53
|
let cancelled = false;
|
|
66
54
|
const handle = (event) => {
|
|
67
55
|
setState((prev) => reduce(prev, event));
|
|
68
|
-
// The `authenticated` event carries tokens only, so refetch user claims.
|
|
69
56
|
if (event.type === "authenticated") {
|
|
70
57
|
client.getUser().then((user) => {
|
|
71
58
|
if (!cancelled)
|
|
@@ -5,9 +5,6 @@
|
|
|
5
5
|
* `returnTo` set to the current path, and renders a configurable
|
|
6
6
|
* `fallback` while the redirect is in flight.
|
|
7
7
|
*
|
|
8
|
-
* Avoids the `withAuthenticationRequired` re-mount footgun (the HOC
|
|
9
|
-
* isn't created in render; this component just gates its children).
|
|
10
|
-
*
|
|
11
8
|
* @module
|
|
12
9
|
*/
|
|
13
10
|
import { type ReactNode } from "react";
|
|
@@ -6,9 +6,6 @@
|
|
|
6
6
|
* `returnTo` set to the current path, and renders a configurable
|
|
7
7
|
* `fallback` while the redirect is in flight.
|
|
8
8
|
*
|
|
9
|
-
* Avoids the `withAuthenticationRequired` re-mount footgun (the HOC
|
|
10
|
-
* isn't created in render; this component just gates its children).
|
|
11
|
-
*
|
|
12
9
|
* @module
|
|
13
10
|
*/
|
|
14
11
|
import { useEffect } from "react";
|
package/esm/react/testing.d.ts
CHANGED
|
@@ -132,8 +132,9 @@ export declare class MockOAuth2Client extends OAuth2ClientBase implements MockOA
|
|
|
132
132
|
setSessionExpiresIn(seconds: number | null): void;
|
|
133
133
|
}
|
|
134
134
|
/**
|
|
135
|
-
* A real `BffClient` whose
|
|
136
|
-
* instead of the BFF.
|
|
135
|
+
* A real `BffClient` whose session operations, `login`, `logout` and `fetch`
|
|
136
|
+
* answer from mock state or pass through instead of reaching the BFF.
|
|
137
|
+
* `useBffClient()` accepts it.
|
|
137
138
|
*/
|
|
138
139
|
export declare class MockBffClient extends BffClient implements MockOAuth2Controls {
|
|
139
140
|
#private;
|
package/esm/react/testing.js
CHANGED
|
@@ -47,7 +47,6 @@ import "../_dnt.polyfills.js";
|
|
|
47
47
|
import { useMemo } from "react";
|
|
48
48
|
import { BffClient, DirectClient, OAuth2ClientBase, } from "../client/mod.js";
|
|
49
49
|
import { OAuth2Context } from "./context.js";
|
|
50
|
-
/** The mock behavior each client class delegates to. */
|
|
51
50
|
class MockCore {
|
|
52
51
|
initialState;
|
|
53
52
|
renewCount = 0;
|
|
@@ -197,8 +196,9 @@ export class MockOAuth2Client extends OAuth2ClientBase {
|
|
|
197
196
|
}
|
|
198
197
|
}
|
|
199
198
|
/**
|
|
200
|
-
* A real `BffClient` whose
|
|
201
|
-
* instead of the BFF.
|
|
199
|
+
* A real `BffClient` whose session operations, `login`, `logout` and `fetch`
|
|
200
|
+
* answer from mock state or pass through instead of reaching the BFF.
|
|
201
|
+
* `useBffClient()` accepts it.
|
|
202
202
|
*/
|
|
203
203
|
export class MockBffClient extends BffClient {
|
|
204
204
|
#core;
|
|
@@ -3,7 +3,7 @@ import { type BaseLoginOptions, BffClient, DirectClient, type LogoutOptions, typ
|
|
|
3
3
|
export interface UseOAuth2Result {
|
|
4
4
|
/** True iff a user is authenticated. */
|
|
5
5
|
isAuthenticated: boolean;
|
|
6
|
-
/** True
|
|
6
|
+
/** True while the provider's initial session probe is in flight. */
|
|
7
7
|
isLoading: boolean;
|
|
8
8
|
/** Current user claims, or `null`. */
|
|
9
9
|
user: UserInfoClaims | null;
|