okengine 0.4.3 → 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.
Files changed (127) hide show
  1. package/package.json +3 -1
  2. package/site/content/docs/ai/index.mdx +24 -0
  3. package/site/content/docs/ai/llms-txt.mdx +3 -0
  4. package/site/content/docs/ai/meta.json +1 -1
  5. package/site/content/docs/console/gates.mdx +46 -8
  6. package/site/content/docs/console/index.mdx +54 -0
  7. package/site/content/docs/console/meta.json +1 -0
  8. package/site/content/docs/elements/gate.mdx +187 -48
  9. package/site/content/docs/elements/index.mdx +45 -0
  10. package/site/content/docs/elements/meta.json +1 -1
  11. package/site/content/docs/get-started/basic-usage.mdx +4 -3
  12. package/site/content/docs/get-started/index.mdx +33 -0
  13. package/site/content/docs/get-started/meta.json +1 -1
  14. package/site/content/docs/index.mdx +9 -31
  15. package/site/content/docs/plugins/anonymous.mdx +95 -0
  16. package/site/content/docs/plugins/compression.mdx +2 -2
  17. package/site/content/docs/plugins/cors.mdx +2 -2
  18. package/site/content/docs/plugins/csrf.mdx +2 -2
  19. package/site/content/docs/plugins/email-otp.mdx +111 -0
  20. package/site/content/docs/plugins/{security-headers.mdx → headers.mdx} +1 -1
  21. package/site/content/docs/plugins/index.mdx +69 -0
  22. package/site/content/docs/plugins/magic-link.mdx +112 -0
  23. package/site/content/docs/plugins/maintenance-mode.mdx +8 -8
  24. package/site/content/docs/plugins/meta.json +10 -1
  25. package/site/content/docs/plugins/passkey.mdx +128 -0
  26. package/site/content/docs/plugins/phone-number.mdx +111 -0
  27. package/site/content/docs/plugins/two-factor.mdx +116 -0
  28. package/site/content/docs/plugins/username.mdx +117 -0
  29. package/site/content/docs/reference/client.mdx +331 -0
  30. package/site/content/docs/reference/fx.mdx +20 -5
  31. package/site/content/docs/reference/index.mdx +45 -0
  32. package/site/content/docs/reference/meta.json +11 -1
  33. package/site/content/docs/reference/plugins.mdx +25 -14
  34. package/src/auth/auth.test.ts +20 -2
  35. package/src/auth/bindings.ts +439 -0
  36. package/src/auth/breach-check.ts +112 -0
  37. package/src/auth/config.ts +288 -0
  38. package/src/auth/cookies.ts +123 -0
  39. package/src/auth/gate-auth.test.ts +379 -0
  40. package/src/auth/identity.ts +190 -0
  41. package/src/auth/index.ts +117 -1
  42. package/src/auth/method-context.ts +33 -0
  43. package/src/auth/operator.ts +27 -1
  44. package/src/auth/password-policy.test.ts +126 -0
  45. package/src/auth/password-policy.ts +77 -0
  46. package/src/auth/plugin.ts +62 -4
  47. package/src/auth/rate.ts +45 -0
  48. package/src/auth/schema.ts +260 -0
  49. package/src/auth/secondary-storage.ts +37 -0
  50. package/src/auth/sessions.ts +58 -1
  51. package/src/auth/tables.ts +4 -0
  52. package/src/auth/verification.ts +78 -0
  53. package/src/cli/dev.test.ts +3 -3
  54. package/src/cli/schema.ts +95 -23
  55. package/src/client/auth.ts +120 -0
  56. package/src/client-react/index.ts +93 -0
  57. package/src/compiler/aot.test.ts +2 -1
  58. package/src/compiler/extract.ts +19 -0
  59. package/src/compiler/response.ts +16 -2
  60. package/src/console/server/app.ts +10 -6
  61. package/src/console/server/auth-rate.test.ts +3 -3
  62. package/src/console/server/bind.ts +12 -1
  63. package/src/console/server/channels.test.ts +1 -1
  64. package/src/console/server/console-gates.ts +14 -0
  65. package/src/console/server/console.test.ts +6 -6
  66. package/src/console/server/flows-invoke.test.ts +2 -2
  67. package/src/console/server/flows.ts +2 -0
  68. package/src/console/server/gates.ts +8 -1
  69. package/src/console/server/operator-db.test.ts +4 -4
  70. package/src/console/server/operator-db.ts +22 -4
  71. package/src/console/server/security.gate.test.ts +3 -3
  72. package/src/console/ui/gates/fixture.ts +4 -0
  73. package/src/console/ui/gates/types.ts +2 -0
  74. package/src/console/ui/shell/client.ts +1 -0
  75. package/src/elements/gate/boot.ts +136 -0
  76. package/src/elements/gate/config.ts +69 -0
  77. package/src/elements/gate/declare.ts +51 -1
  78. package/src/elements/gate/runtime.ts +3 -1
  79. package/src/elements/gate.test.ts +77 -0
  80. package/src/elements/gate.ts +20 -1
  81. package/src/elements/index.ts +8 -0
  82. package/src/index.ts +11 -0
  83. package/src/kernel/app.ts +253 -32
  84. package/src/kernel/boot.test.ts +40 -3
  85. package/src/kernel/boot.ts +8 -0
  86. package/src/kernel/call.test.ts +46 -2
  87. package/src/kernel/edge.test.ts +3 -3
  88. package/src/kernel/flow.test.ts +2 -2
  89. package/src/kernel/fx.test.ts +1 -0
  90. package/src/kernel/fx.ts +60 -0
  91. package/src/kernel/hooks.test.ts +4 -4
  92. package/src/kernel/index.ts +12 -0
  93. package/src/kernel/pipeline.test.ts +12 -8
  94. package/src/kernel/pipeline.ts +23 -4
  95. package/src/kernel/plugin/decorate.test.ts +3 -3
  96. package/src/kernel/plugin/scoping.test.ts +3 -3
  97. package/src/kernel/plugin-elements.test.ts +51 -0
  98. package/src/kernel/plugin-needs.test.ts +83 -0
  99. package/src/kernel/plugin-needs.ts +129 -0
  100. package/src/kernel/plugin.ts +101 -0
  101. package/src/kernel/registry-isolation.test.ts +5 -5
  102. package/src/kernel/registry.ts +102 -3
  103. package/src/manifest/types.ts +2 -0
  104. package/src/plugins/anonymous.ts +58 -0
  105. package/src/plugins/auth/shared.ts +121 -0
  106. package/src/plugins/auth-methods.test.ts +176 -0
  107. package/src/plugins/compression.test.ts +5 -5
  108. package/src/plugins/config-source.test.ts +1 -1
  109. package/src/plugins/cors.test.ts +16 -10
  110. package/src/plugins/csrf.test.ts +1 -1
  111. package/src/plugins/email-otp.ts +161 -0
  112. package/src/plugins/index.ts +31 -0
  113. package/src/plugins/ip-allowlist.test.ts +19 -9
  114. package/src/plugins/magic-link.ts +163 -0
  115. package/src/plugins/maintenance-mode.test.ts +9 -5
  116. package/src/plugins/passkey.ts +216 -0
  117. package/src/plugins/phone-number.ts +149 -0
  118. package/src/plugins/security-headers.test.ts +14 -14
  119. package/src/plugins/two-factor.ts +249 -0
  120. package/src/plugins/username.ts +148 -0
  121. package/src/runs/runs.test.ts +6 -2
  122. package/src/runtime/primitives.ts +37 -4
  123. package/src/runtime/serve.test.ts +3 -2
  124. package/src/runtime/types.ts +25 -2
  125. package/src/test/create-test-app.test.ts +1 -1
  126. package/src/test/create-test-app.ts +4 -1
  127. package/src/test/provisions.integration.test.ts +1 -1
@@ -0,0 +1,128 @@
1
+ ---
2
+ title: "Passkey"
3
+ description: "Official plugin — simplified WebAuthn register and authenticate under /auth."
4
+ icon: "FingerprintPattern"
5
+ source: "docs/spec/unified-theory.md"
6
+ ---
7
+
8
+ `passkey()` adds register and authenticate Flows for passkey-shaped credentials (`oke_passkeys`).
9
+ v1 is a simplified ceremony — options return a challenge; register/authenticate accept the
10
+ payload your client posts (not a full browser WebAuthn SDK).
11
+
12
+ <Callout title="The one rule">
13
+ Enable `gate.auth`, then `.plug(passkey())`. Registration needs a Bearer session; authenticate is
14
+ public. Wire `navigator.credentials` (or tests) yourself — the plugin stores and verifies the
15
+ posted fields.
16
+ </Callout>
17
+
18
+ ## Quick start
19
+
20
+ <Steps>
21
+
22
+ <Step>
23
+ ### Plug it
24
+
25
+ ```typescript title="src/app.ts"
26
+ import { oke } from "okengine";
27
+ import { passkey } from "okengine/plugins";
28
+
29
+ export const app = oke({
30
+ name: "shop",
31
+ env: "local",
32
+ gate: { auth: {} },
33
+ }).plug(passkey());
34
+ ```
35
+
36
+ </Step>
37
+
38
+ <Step>
39
+ ### Register (session required)
40
+
41
+ Wire Bearer on `createClient` (`auth.getToken` / `memorySession`) — calls take input only.
42
+
43
+ ```typescript
44
+ const opts = await api.auth.passkeyRegisterOptions({});
45
+ // opts.data: { challenge, rpId, userId }
46
+
47
+ await api.auth.passkeyRegister({
48
+ credentialId: "...",
49
+ publicKey: "...",
50
+ userId: opts.data!.userId,
51
+ challenge: opts.data!.challenge,
52
+ });
53
+ ```
54
+
55
+ Paths: `POST /auth/passkey/register/options`, `POST /auth/passkey/register`.
56
+
57
+ </Step>
58
+
59
+ <Step>
60
+ ### Authenticate
61
+
62
+ ```typescript
63
+ await api.auth.passkeyAuthenticateOptions({});
64
+ const { data } = await api.auth.passkeyAuthenticate({
65
+ credentialId: "...",
66
+ userId: "...",
67
+ });
68
+ ```
69
+
70
+ Paths: `POST /auth/passkey/authenticate/options`, `POST /auth/passkey/authenticate`.
71
+ v1 issues a session when the stored credential matches `userId`.
72
+
73
+ </Step>
74
+
75
+ </Steps>
76
+
77
+ ## Options
78
+
79
+ | Option | Type | Default | Meaning |
80
+ | ------------ | ------------------- | ------------- | -------------------------------- |
81
+ | `secret` | `string` | active\* | HMAC secret (\*from `gate.auth`) |
82
+ | `sessions` | `SessionStore` | active\* | Session store |
83
+ | `now` | `() => number` | `Date.now` | Injectable clock |
84
+ | `passkeys` | `PasskeyStore` | new | Credential → user mapping |
85
+ | `challenges` | `VerificationStore` | new | Registration / auth challenges |
86
+ | `rpId` | `string` | `"localhost"` | Relying party id in options |
87
+
88
+ ## Surfaces
89
+
90
+ | Flow | Path | Gate |
91
+ | --------------------------------- | ----------------------------------------- | ------------------------ |
92
+ | `auth.passkeyRegisterOptions` | `POST /auth/passkey/register/options` | session + bearer |
93
+ | `auth.passkeyRegister` | `POST /auth/passkey/register` | session + bearer |
94
+ | `auth.passkeyAuthenticateOptions` | `POST /auth/passkey/authenticate/options` | `gate.public` + otp rate |
95
+ | `auth.passkeyAuthenticate` | `POST /auth/passkey/authenticate` | `gate.public` + otp rate |
96
+
97
+ **Consequence:** production apps should replace the simplified verify with a standards-compliant
98
+ WebAuthn verifier when you leave local/test.
99
+
100
+ ## Troubleshooting
101
+
102
+ <Accordions>
103
+ <Accordion title="register fails with unauthenticated">
104
+
105
+ Sign in with another method first. `userId` in the body must match the Bearer session.
106
+
107
+ </Accordion>
108
+ <Accordion title="authenticate returns invalid_credentials">
109
+
110
+ Unknown `credentialId`, or `userId` does not match the stored credential. Re-run registration
111
+ after a successful session.
112
+
113
+ </Accordion>
114
+ </Accordions>
115
+
116
+ ## Learn more
117
+
118
+ - [Two-factor](/docs/plugins/two-factor) — TOTP step-up
119
+ - [Gate](/docs/elements/gate) — `gate.auth`
120
+ - [Client](/docs/reference/client) — calling `/auth` from the browser
121
+
122
+ ## Next
123
+
124
+ <Cards>
125
+ <Card title="Two-factor" description="TOTP enable / verify." href="/docs/plugins/two-factor" />
126
+ <Card title="Gate" description="Builtin auth and policies." href="/docs/elements/gate" />
127
+ <Card title="Anonymous" description="Guest sessions." href="/docs/plugins/anonymous" />
128
+ </Cards>
@@ -0,0 +1,111 @@
1
+ ---
2
+ title: "Phone number"
3
+ description: "Official plugin — E.164 phone OTP request and verify under /auth."
4
+ icon: "Smartphone"
5
+ source: "docs/spec/unified-theory.md"
6
+ ---
7
+
8
+ `phoneNumber()` signs people in with a phone number in E.164 form (`+15551234567`). Codes are
9
+ 6 digits, hashed, 10 minutes, 5 attempts — same security shape as email OTP.
10
+
11
+ <Callout title="The one rule">
12
+ Enable `gate.auth`, then `.plug(phoneNumber())`. Reject non-E.164 numbers. SMS Channel delivery is
13
+ not wired yet — use `exposeDevOtp` locally. Prefer stronger methods when phone is the only factor.
14
+ </Callout>
15
+
16
+ ## Quick start
17
+
18
+ <Steps>
19
+
20
+ <Step>
21
+ ### Plug it
22
+
23
+ ```typescript title="src/app.ts"
24
+ import { oke } from "okengine";
25
+ import { phoneNumber } from "okengine/plugins";
26
+
27
+ export const app = oke({
28
+ name: "shop",
29
+ env: "local",
30
+ gate: { auth: {} },
31
+ }).plug(phoneNumber({ exposeDevOtp: true }));
32
+ ```
33
+
34
+ </Step>
35
+
36
+ <Step>
37
+ ### Request a code
38
+
39
+ ```typescript
40
+ const { data, error } = await api.auth.requestPhoneOtp({ phone: "+15551234567" });
41
+ ```
42
+
43
+ `POST /auth/phone/request`. Invalid E.164 → `AuthFailed` / `invalid_phone`.
44
+
45
+ </Step>
46
+
47
+ <Step>
48
+ ### Verify
49
+
50
+ ```typescript
51
+ const { data } = await api.auth.verifyPhoneOtp({
52
+ phone: "+15551234567",
53
+ otp: data!.devOtp!,
54
+ });
55
+ ```
56
+
57
+ `POST /auth/phone/verify` — first success creates a phone → `userId` mapping.
58
+
59
+ </Step>
60
+
61
+ </Steps>
62
+
63
+ ## Options
64
+
65
+ | Option | Type | Default | Meaning |
66
+ | --------------- | ------------------- | -------- | --------------------------------------- |
67
+ | `secret` | `string` | active\* | HMAC secret (\*from `gate.auth`) |
68
+ | `sessions` | `SessionStore` | active\* | Session store |
69
+ | `ttlMs` | `number` | 10m | Challenge lifetime |
70
+ | `exposeDevOtp` | `boolean` | `false` | Include raw OTP in the request response |
71
+ | `phones` | `PhoneStore` | new | Phone → userId map |
72
+ | `verifications` | `VerificationStore` | new | Challenge store |
73
+
74
+ ## Surfaces
75
+
76
+ | Flow | Path | Gate |
77
+ | ---------------------- | -------------------------- | ------------------------ |
78
+ | `auth.requestPhoneOtp` | `POST /auth/phone/request` | `gate.public` + otp rate |
79
+ | `auth.verifyPhoneOtp` | `POST /auth/phone/verify` | `gate.public` + otp rate |
80
+
81
+ E.164 pattern: `^\+[1-9]\d{7,14}$`.
82
+
83
+ ## Troubleshooting
84
+
85
+ <Accordions>
86
+ <Accordion title="invalid_phone">
87
+
88
+ Number must start with `+` and a non-zero country digit, then 7–14 more digits. No spaces or
89
+ dashes.
90
+
91
+ </Accordion>
92
+ <Accordion title="No SMS arrived">
93
+
94
+ v1 does not send SMS. Use `exposeDevOtp` in local/test, or deliver via your own Channel Flow.
95
+
96
+ </Accordion>
97
+ </Accordions>
98
+
99
+ ## Learn more
100
+
101
+ - [Email OTP](/docs/plugins/email-otp) — email variant of the same OTP rules
102
+ - [Gate](/docs/elements/gate) — `gate.auth`
103
+ - [Channel](/docs/elements/channel) — when you wire SMS yourself
104
+
105
+ ## Next
106
+
107
+ <Cards>
108
+ <Card title="Email OTP" description="Six-digit email codes." href="/docs/plugins/email-otp" />
109
+ <Card title="Two-factor" description="TOTP step-up." href="/docs/plugins/two-factor" />
110
+ <Card title="Gate" description="Builtin auth and policies." href="/docs/elements/gate" />
111
+ </Cards>
@@ -0,0 +1,116 @@
1
+ ---
2
+ title: "Two-factor"
3
+ description: "Official plugin — TOTP enable, verify, and disable for an authenticated session."
4
+ icon: "LockKeyhole"
5
+ source: "docs/spec/unified-theory.md"
6
+ ---
7
+
8
+ `twoFactor()` adds RFC 6238 TOTP (HMAC-SHA1, 6 digits, 30s) after someone already has a session.
9
+ Enable returns a secret, `otpauth://` URL, and recovery codes; verify mints a new session.
10
+
11
+ <Callout title="The one rule">
12
+ Enable `gate.auth`, then `.plug(twoFactor())`. Enable and disable need a Bearer session —
13
+ verify is public and takes `{ userId, code }` after password (or other) sign-in.
14
+ </Callout>
15
+
16
+ ## Quick start
17
+
18
+ <Steps>
19
+
20
+ <Step>
21
+ ### Plug it
22
+
23
+ ```typescript title="src/app.ts"
24
+ import { oke } from "okengine";
25
+ import { twoFactor } from "okengine/plugins";
26
+
27
+ export const app = oke({
28
+ name: "shop",
29
+ env: "local",
30
+ gate: { auth: {} },
31
+ }).plug(twoFactor());
32
+ ```
33
+
34
+ </Step>
35
+
36
+ <Step>
37
+ ### Enable (session required)
38
+
39
+ Wire Bearer on `createClient` (`auth.getToken` / `memorySession`) — calls take input only.
40
+
41
+ ```typescript
42
+ const { data } = await api.auth.twoFactorEnable({});
43
+ // data.secret, data.otpauthUrl, data.recoveryCodes
44
+ ```
45
+
46
+ `POST /auth/two-factor/enable` — writes `oke_two_factor`. Store recovery codes once; they are
47
+ shown only here.
48
+
49
+ </Step>
50
+
51
+ <Step>
52
+ ### Verify a code
53
+
54
+ ```typescript
55
+ const { data } = await api.auth.twoFactorVerify({ userId, code: "123456" });
56
+ // hybrid session tokens — recovery codes also accepted once each
57
+ ```
58
+
59
+ `POST /auth/two-factor/verify`. Missing / disabled factor or bad code → `AuthFailed` /
60
+ `invalid_credentials`. Disable: `api.auth.twoFactorDisable` (Bearer via `auth.getToken`).
61
+
62
+ </Step>
63
+
64
+ </Steps>
65
+
66
+ ## Options
67
+
68
+ | Option | Type | Default | Meaning |
69
+ | ---------- | ---------------- | ---------- | -------------------------------- |
70
+ | `secret` | `string` | active\* | HMAC secret (\*from `gate.auth`) |
71
+ | `sessions` | `SessionStore` | active\* | Session store |
72
+ | `now` | `() => number` | `Date.now` | Injectable clock |
73
+ | `factors` | `TwoFactorStore` | new | Per-user TOTP + recovery hashes |
74
+ | `issuer` | `string` | `"oke"` | Label in `otpauth://` URLs |
75
+
76
+ ## Surfaces
77
+
78
+ | Flow | Path | Gate |
79
+ | ----------------------- | ------------------------------- | ------------------------ |
80
+ | `auth.twoFactorEnable` | `POST /auth/two-factor/enable` | session + bearer |
81
+ | `auth.twoFactorVerify` | `POST /auth/two-factor/verify` | `gate.public` + otp rate |
82
+ | `auth.twoFactorDisable` | `POST /auth/two-factor/disable` | session + bearer |
83
+
84
+ **Consequence:** verify issues a full session for `userId` — use it as the step after first-factor
85
+ sign-in when the account has 2FA enabled.
86
+
87
+ ## Troubleshooting
88
+
89
+ <Accordions>
90
+ <Accordion title="twoFactorEnable returns AuthFailed unauthenticated">
91
+
92
+ Wire a session into `createClient` (`auth.getToken` / `memorySession`) from email/password
93
+ (or another method) first — enable is gated on Bearer.
94
+
95
+ </Accordion>
96
+ <Accordion title="verify always fails">
97
+
98
+ Code must be six digits. Check clock skew (±1 window), and that you enrolled the `secret` from
99
+ enable. A recovery code works once, then is consumed.
100
+
101
+ </Accordion>
102
+ </Accordions>
103
+
104
+ ## Learn more
105
+
106
+ - [Passkey](/docs/plugins/passkey) — WebAuthn-shaped register / authenticate
107
+ - [Gate](/docs/elements/gate) — session + policies
108
+ - [Username](/docs/plugins/username) — first factor to enroll against
109
+
110
+ ## Next
111
+
112
+ <Cards>
113
+ <Card title="Passkey" description="WebAuthn register and assert." href="/docs/plugins/passkey" />
114
+ <Card title="Gate" description="Builtin auth and policies." href="/docs/elements/gate" />
115
+ <Card title="Email OTP" description="Passwordless email codes." href="/docs/plugins/email-otp" />
116
+ </Cards>
@@ -0,0 +1,117 @@
1
+ ---
2
+ title: "Username"
3
+ description: "Official plugin — username + password sign-up and sign-in under /auth, plugged onto gate.auth."
4
+ icon: "UserRound"
5
+ source: "docs/spec/unified-theory.md"
6
+ ---
7
+
8
+ `username()` lets people register and sign in with a username instead of email. It adds two public
9
+ Flows under `/auth` and contributes the `oke_usernames` table.
10
+
11
+ <Callout title="The one rule">
12
+ Enable `gate.auth` first, then `.plug(username())`. The plugin `.needs("auth")` and joins the HTTP
13
+ router via Bindings — not registry metadata alone.
14
+ </Callout>
15
+
16
+ ## Quick start
17
+
18
+ <Steps>
19
+
20
+ <Step>
21
+ ### Plug it
22
+
23
+ ```typescript title="src/app.ts"
24
+ import { oke } from "okengine";
25
+ import { username } from "okengine/plugins";
26
+
27
+ export const app = oke({
28
+ name: "shop",
29
+ env: "local",
30
+ gate: { auth: {} },
31
+ }).plug(username());
32
+ ```
33
+
34
+ </Step>
35
+
36
+ <Step>
37
+ ### Sign up
38
+
39
+ ```typescript
40
+ const { data, error } = await api.auth.signUpUsername({
41
+ username: "ali",
42
+ password: "CorrectHorse1",
43
+ });
44
+ ```
45
+
46
+ `POST /auth/sign-up/username` — usernames are normalized to lowercase; allowed pattern
47
+ `[a-z0-9._-]{3,64}`.
48
+
49
+ </Step>
50
+
51
+ <Step>
52
+ ### Sign in
53
+
54
+ ```typescript
55
+ const { data } = await api.auth.signInUsername({
56
+ username: "ali",
57
+ password: "CorrectHorse1",
58
+ });
59
+ // data: accessToken, refreshToken, accessExpiresAt, userId
60
+ ```
61
+
62
+ Unknown username and bad password both return `AuthFailed` with
63
+ `reason: "invalid_credentials"` (enumeration-safe).
64
+
65
+ </Step>
66
+
67
+ </Steps>
68
+
69
+ ## Options
70
+
71
+ | Option | Type | Default | Meaning |
72
+ | ----------- | --------------- | ---------- | ----------------------------------------------------------- |
73
+ | `secret` | `string` | active\* | HMAC secret (\*from `gate.auth` when plugged after `oke()`) |
74
+ | `sessions` | `SessionStore` | active\* | Session store shared with Gate auth |
75
+ | `now` | `() => number` | `Date.now` | Injectable clock |
76
+ | `usernames` | `UsernameStore` | new map | Shared in-memory credential store |
77
+
78
+ ## Surfaces
79
+
80
+ | Flow | Path | Gate |
81
+ | --------------------- | ----------------------------- | ---------------------------- |
82
+ | `auth.signUpUsername` | `POST /auth/sign-up/username` | `gate.public` + sign-up rate |
83
+ | `auth.signInUsername` | `POST /auth/sign-in/username` | `gate.public` + sign-in rate |
84
+
85
+ ## Troubleshooting
86
+
87
+ <Accordions>
88
+ <Accordion title="plugin boot failed — needs &quot;auth&quot;">
89
+
90
+ Set `oke({ gate: { auth: { … } } })` before `.plug(username())`.
91
+
92
+ </Accordion>
93
+ <Accordion title="AuthFailed invalid_credentials on sign-up">
94
+
95
+ Username taken, or it fails the `[a-z0-9._-]{3,64}` pattern after lowercasing. Same error shape
96
+ on purpose — do not treat it as "exists" in the UI.
97
+
98
+ </Accordion>
99
+ </Accordions>
100
+
101
+ ## Learn more
102
+
103
+ - [Gate](/docs/elements/gate) — `gate.auth` and posture
104
+ - [Plugins](/docs/plugins) — all auth method plugins
105
+ - [Client](/docs/reference/client) — `createClient` + `memorySession`
106
+
107
+ ## Next
108
+
109
+ <Cards>
110
+ <Card
111
+ title="Anonymous"
112
+ description="Session without a password."
113
+ href="/docs/plugins/anonymous"
114
+ />
115
+ <Card title="Gate" description="Builtin auth and policies." href="/docs/elements/gate" />
116
+ <Card title="Magic link" description="Email link sign-in." href="/docs/plugins/magic-link" />
117
+ </Cards>