@tktchurch/auth 0.9.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,210 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [0.9.1] - 2026-06-25
6
+
7
+ ### Changed
8
+
9
+ - Dual-build pipeline: public npmjs publishes a **consumer** SDK (OAuth/OIDC client
10
+ namespaces only); GitHub Packages publishes the **full** internal SDK with admin
11
+ console modules, `request`/`fetchWithAuth`, and source maps.
12
+ - Public consumer build is minified, ships without source maps, and does not export
13
+ `DEFAULT_BASE_URL` or admin TypeScript types.
14
+ - `package.json` repository metadata now points at `tktchurch/auth-sdk-js`.
15
+
16
+ ### Added
17
+
18
+ - `build:consumer`, `build:full`, `release:check:consumer` scripts.
19
+ - `tests/consumer-build.test.ts` guards the public artifact surface.
20
+
21
+ ## [0.8.0] - 2026-06-24
22
+
23
+ ### Changed
24
+
25
+ - `accounts/` and `developers/` Nuxt server utilities now use `@tktchurch/auth` for
26
+ PKCE authorization start, token exchange/refresh/revoke, user profile fetch, and
27
+ `sanitizePostAuthRedirect`.
28
+ - Privacy UI stub pages: accounts `/account/privacy`, developers `/admin/privacy`
29
+ (hook points for upcoming `auth.privacy.*`).
30
+
31
+ ## [0.6.0] - 2026-06-24
32
+
33
+ ### Added
34
+
35
+ - Platform modules: `families.*`, `dependents.*` (guardian consent), `clients.providers.*`.
36
+ - Client API keys: `clients.apiKeys.list/create/delete` backed by new OAuth
37
+ `GET/POST/DELETE /api/v1/clients/:id/api-keys` routes.
38
+ - OAuth backend admin reads: `GET /api/v1/users/:id/mfa/devices`,
39
+ `GET /api/v1/users/:id/webauthn/credentials`, and `GET /api/v1/sessions?user_id=`
40
+ for console user detail pages.
41
+
42
+ ### Tests
43
+
44
+ - Unit coverage in `tests/phase051-platform.test.ts`; extended local-stack and Playwright suites.
45
+
46
+ ## [0.5.2] - 2026-06-24
47
+
48
+ ### Added
49
+
50
+ - `clients.apiKeys.*` SDK methods (see 0.6.0 backend implementation).
51
+
52
+ ## [0.5.1] - 2026-06-24
53
+
54
+ ### Added
55
+
56
+ - Migration parity: `oauth.discoverAuthorizationServer()`, `authorize.probeAuthorize()`,
57
+ `user.uploadAvatar()`, `memberDirectory.lookup()`, `federated.*` URL builders and
58
+ link finalize HTTP methods.
59
+ - Admin reads: `user.admin.getMfaDevices()`, `user.admin.getWebAuthnCredentials()`.
60
+ - List filter wiring: `clients.list({ isActive })`, expanded `UserListQuery`,
61
+ `RoleListQuery`, `SessionListQuery`, `AuditLogListQuery`.
62
+
63
+ ### Changed
64
+
65
+ - `webauthn.removeCredential` accepts optional `{ password }` body.
66
+ - `http.ts` supports `FormData` multipart uploads and `redirect: manual`.
67
+ - README: `sessions.revokeOthers` → `revokeAll`.
68
+
69
+ ## [0.5.0] - 2026-06-24
70
+
71
+ ### Added
72
+
73
+ - **Full API parity** with the TKTChurch OAuth backend — user-facing and admin
74
+ console surfaces used by `accounts` / `developers`.
75
+ - User modules: `authorize.consent` / `consentWithCredentials`, `oidc.jwks`,
76
+ `token.tokenExchange` (RFC 8693), `flow.initRecovery` / `executeRecoveryStep`,
77
+ `passwordReset.*`, `mfa.*`, `user` self-service (`updateMe`, `changePassword`,
78
+ recovery contacts, identities), `consents.me.*`, `maintenance.status`,
79
+ `oauth.publicClient`.
80
+ - Admin modules: `clients`, `scopes`, `roles`, `permissions`, `organizations`,
81
+ `auditLogs`, `dashboard`, `jwtKeys`, `webhooks`, `customAttributes`,
82
+ `authMethods`, `authenticationFlows`, `comms` (SMS/email providers, templates,
83
+ logs, test phones), and `user.admin` CRUD.
84
+ - Shared pagination helpers (`normalizePageQuery`, `buildQueryString`,
85
+ `mapPageResponse`) with `MAX_PER_PAGE` cap.
86
+ - Unit tests for all new modules; example smoke tests for PKCE route helpers;
87
+ gated local-stack integration tests (`bun run test:local`).
88
+
89
+ ### Changed
90
+
91
+ - `token.revoke` and `token.introspect` now include `client_id` / `client_secret`
92
+ in the request body (required by the OAuth server for RFC 7009 / introspection).
93
+
94
+ ### Added (0.5.0 continued)
95
+
96
+ - Expanded local-stack integration tests: PKCE full cycle, OIDC/JWKS, flow init,
97
+ public client metadata.
98
+ - Playwright API e2e suite (`tests/e2e/`) for live backend + security invariants.
99
+ - `bun run test:local:env` and `bun run test:e2e:env` scripts (source `oauth/.env`).
100
+
101
+
102
+ ### Verified
103
+
104
+ - `bun run release:check` (74 unit tests + 6 gated integration tests)
105
+
106
+ ## [0.4.0] - 2026-06-24
107
+
108
+ ### Removed (breaking)
109
+
110
+ - `createLocalStorageTokenStorage` and the `@tktchurch/auth/storage/localStorage`
111
+ package subpath. Browser `localStorage` is an XSS sink for OAuth tokens; the
112
+ SDK no longer ships a persistence adapter for it.
113
+
114
+ ### Added
115
+
116
+ - Token storage validation exports: `assertValidAuthTokens`, `parseStoredAuthTokens`,
117
+ `serializeAuthTokens`, `validateStorageKey`, `safeParseStoredJson`,
118
+ `DEFAULT_TOKEN_STORAGE_KEY`, `MAX_STORED_TOKEN_BYTES`.
119
+ - `allowInsecureTransport` config flag (default `false`) — rejects non-HTTPS
120
+ `baseUrl` outside loopback hosts.
121
+ - [`SECURITY.md`](./SECURITY.md) threat model and integrator checklist.
122
+ - Hardened examples with PKCE redirect flow, signed OAuth session cookies, safe
123
+ error mapping, and strict input validation ([`examples/`](./examples/)).
124
+
125
+ ### Changed
126
+
127
+ - Examples now demonstrate authorization code + PKCE as the primary login path;
128
+ password grant routes are retained for local dev/testing only.
129
+
130
+ ### Migration
131
+
132
+ 1. Remove `createLocalStorageTokenStorage()` — not replaced.
133
+ 2. Use HttpOnly cookies for refresh tokens via server routes (see examples).
134
+ 3. Implement custom `TokenStorage` with exported validators for platform-specific
135
+ secure backends (Keychain, Keystore).
136
+
137
+ ### Verified
138
+
139
+ - `bun run typecheck`
140
+ - `bun run test`
141
+ - `bun run build`
142
+
143
+ ## [0.3.0] - 2026-06-24
144
+
145
+ ### Added
146
+
147
+ - **Authorization Code + PKCE redirect flow** (`client.authorize`), the headline
148
+ capability that lets frontends adopt OAuth without re-implementing PKCE/state
149
+ plumbing per app:
150
+ - `authorize.createRequest()` — generates CSPRNG `state` + `nonce` + PKCE
151
+ (`S256` by default) and returns the authorization URL plus the values to
152
+ persist (`state`, `nonce`, `codeVerifier`, `redirectUri`).
153
+ - `authorize.parseCallback()` — normalizes a callback URL/query string.
154
+ - `authorize.handleCallback()` — one call that verifies `state`
155
+ (constant-time), surfaces server errors, and exchanges the code for tokens.
156
+ - Standalone PKCE/CSRF primitives: `generatePkce`, `generateCodeVerifier`,
157
+ `deriveCodeChallenge`, `generateState`, `generateNonce`, `randomUrlSafeString`,
158
+ `timingSafeEqual` — all backed by the platform Web Crypto CSPRNG.
159
+ - `sanitizePostAuthRedirect()` open-redirect guard (rejects protocol-relative,
160
+ backslash-smuggled, scheme-bearing, and CRLF targets).
161
+ - `oidc.discover()` — fetches and maps `/.well-known/openid-configuration`.
162
+ - Broader public type exports (`AuthorizationUrlOptions`, `AuthorizationRequest`,
163
+ `CallbackParams`, `HandleCallbackOptions`, `OidcDiscoveryDocument`, endpoint
164
+ interfaces, `AuthErrorCode`).
165
+
166
+ ### Security
167
+
168
+ - All anti-forgery/PKCE randomness uses `globalThis.crypto.getRandomValues`,
169
+ never `Math.random`.
170
+ - `state` is verified with a constant-time comparison (`timingSafeEqual`).
171
+ - PKCE `codeVerifier` is documented as a server-side secret and never appears in
172
+ the authorization URL.
173
+
174
+ ### Verified
175
+
176
+ - `bun run typecheck`
177
+ - `bun run test` (includes the RFC 7636 Appendix B S256 vector)
178
+ - `bun run build`
179
+
180
+ ## [0.2.0] - 2026-02-26
181
+
182
+ ### Added
183
+
184
+ - Framework-agnostic `@tktchurch/auth` SDK core with typed OAuth, OIDC, AuthFlow, sessions, user, and WebAuthn endpoint wrappers.
185
+ - Token lifecycle support with pluggable storage and `fetchWithAuth` one-retry refresh flow.
186
+ - Nuxt module export `@tktchurch/auth/nuxt` with:
187
+ - `tktAuth` module configuration.
188
+ - injected `$tktAuth` client via `useTktAuth()`.
189
+ - server factory `createTktServerAuthClient()`.
190
+ - cookie helper `useTktRefreshCookieName()`.
191
+ - Next.js and Nuxt3 production examples in `examples/`.
192
+ - Production-gated Nuxt3 integration tests (`tests/nuxt3.production.test.ts`) for login/me/logout patterns.
193
+ - Release metadata and publish hardening:
194
+ - GitHub Packages publish configuration.
195
+ - npmjs public publish workflow and scripts.
196
+ - release workflow and publishing guide.
197
+
198
+ ### Changed
199
+
200
+ - Default SDK endpoint remains `https://prod-auth.tktchurch.com`.
201
+ - Package version bumped to `0.2.0`.
202
+ - Build output now includes the Nuxt module entry (`./nuxt`).
203
+ - Improved strict TypeScript coverage (no implicit `any` in SDK/Nuxt example handlers).
204
+
205
+ ### Verified
206
+
207
+ - `bun run typecheck`
208
+ - `bun run test`
209
+ - `bun run build`
210
+ - `bun run test:nuxt3:prod` (passes when target auth server is reachable and seeded credentials are valid)
package/PUBLISHING.md ADDED
@@ -0,0 +1,121 @@
1
+ # Publishing Guide (`@tktchurch/auth`)
2
+
3
+ This package uses a **dual-build** pipeline. The artifact published to each registry differs:
4
+
5
+ | Registry | Build profile | Contents |
6
+ | --- | --- | --- |
7
+ | **npmjs** (public) | `consumer` | OAuth/OIDC client SDK only — no admin console modules, no `request`/`fetchWithAuth`, no source maps |
8
+ | **GitHub Packages** (private) | `full` | Complete internal SDK (admin CRUD, privacy admin, generic passthrough, source maps) |
9
+
10
+ Registry selection is command/workflow specific. The repo intentionally does not pin `publishConfig.registry` or a scoped `.npmrc` to avoid cross-registry auth conflicts.
11
+
12
+ ## 1. Prerequisites
13
+
14
+ - Repository hosted at `tktchurch/auth-sdk-js`.
15
+ - Package scope is `@tktchurch`.
16
+ - You have permission to publish packages in the `tktchurch` organization.
17
+ - npm scope access for `@tktchurch` (or delegated publish rights).
18
+ - A GitHub token with `write:packages` and `repo` scope (for local GitHub publish).
19
+ - An npm token with publish rights (for local npmjs publish).
20
+ - npm trusted publishing configured for this package/repository (for GitHub Actions npmjs publish).
21
+
22
+ ## 2. Local Release Validation
23
+
24
+ Full internal build (used by `accounts` / `developers` via `file:../auth-sdk-js`):
25
+
26
+ ```bash
27
+ bun run release:check
28
+ ```
29
+
30
+ Consumer build (public npmjs tarball):
31
+
32
+ ```bash
33
+ bun run release:check:consumer
34
+ ```
35
+
36
+ Both run typecheck + tests, then build with the matching profile:
37
+
38
+ | Script | Build |
39
+ | --- | --- |
40
+ | `bun run build` / `build:full` | `BUILD_PROFILE=full` |
41
+ | `bun run build:consumer` | `BUILD_PROFILE=consumer` |
42
+
43
+ ## 3. Local Publish (Manual)
44
+
45
+ ### 3.1 Publish to GitHub Packages (private, full SDK)
46
+
47
+ Set auth token:
48
+
49
+ ```bash
50
+ export NODE_AUTH_TOKEN=ghp_xxx
51
+ ```
52
+
53
+ Publish:
54
+
55
+ ```bash
56
+ bun run publish:github
57
+ ```
58
+
59
+ ### 3.2 Publish to npmjs (public, consumer SDK)
60
+
61
+ Set auth token:
62
+
63
+ ```bash
64
+ export NODE_AUTH_TOKEN=npm_xxx
65
+ ```
66
+
67
+ Publish:
68
+
69
+ ```bash
70
+ bun run publish:npmjs
71
+ ```
72
+
73
+ Both publish scripts run the matching `release:check*` pipeline and pass `--ignore-scripts` so `prepublishOnly` does not rebuild with the wrong profile.
74
+
75
+ ## 4. GitHub Actions Publish
76
+
77
+ Workflow files:
78
+
79
+ 1. `.github/workflows/publish-github-packages.yml` — `build:full` → GitHub Packages
80
+ 2. `.github/workflows/publish-npmjs.yml` — `build:consumer` → npmjs
81
+
82
+ Triggers:
83
+
84
+ 1. Tag push matching `v*` (for example `v0.9.1`)
85
+ 2. Manual dispatch
86
+
87
+ The GitHub Packages workflow installs dependencies, typechecks, tests, builds the **full** bundle, and publishes with `GITHUB_TOKEN`.
88
+
89
+ The npmjs workflow installs dependencies, typechecks, tests, builds the **consumer** bundle, and publishes using trusted publishing (GitHub OIDC) when configured.
90
+
91
+ ## 5. Tagging and Changelog
92
+
93
+ 1. Update `package.json` version.
94
+ 2. Update `CHANGELOG.md`.
95
+ 3. Create and push a release tag:
96
+
97
+ ```bash
98
+ git tag v0.9.1
99
+ git push origin v0.9.1
100
+ ```
101
+
102
+ ## 6. Required Repository Secrets
103
+
104
+ 1. No npmjs token secret is required for npmjs workflow when OIDC trusted publishing is configured.
105
+ 2. GitHub Packages workflow uses `GITHUB_TOKEN` automatically.
106
+
107
+ ## 7. Consumer vs full SDK
108
+
109
+ **Public npm (`consumer`)** ships:
110
+
111
+ - `authorize`, `token`, `oidc`, `flow`, `user` (self-service), `sessions`, `webauthn`, `passwordReset`, `mfa`, `maintenance.status`, `oauth` meta
112
+ - PKCE, redirect sanitization, token storage helpers
113
+ - Nuxt module entry
114
+
115
+ **GitHub Packages (`full`)** additionally ships:
116
+
117
+ - Admin console namespaces (`clients`, `roles`, `auditLogs`, `dashboard`, …)
118
+ - `request()` and `fetchWithAuth()` passthrough helpers
119
+ - `DEFAULT_BASE_URL` export and full TypeScript admin types
120
+
121
+ Internal TKTChurch apps should install from GitHub Packages or use `file:../auth-sdk-js` with `bun run build:full`.
package/README.md ADDED
@@ -0,0 +1,315 @@
1
+ # `@tktchurch/auth`
2
+
3
+ Framework-agnostic auth SDK for TKTChurch OAuth/AuthFlow services.
4
+
5
+ - Default production endpoint: `https://prod-auth.tktchurch.com`
6
+ - Works in browser and Node runtimes (requires `fetch`)
7
+ - Pluggable token storage (`memory` by default)
8
+ - First-class support for AuthFlow endpoints
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ npm install @tktchurch/auth
14
+ ```
15
+
16
+ ## Quick Start
17
+
18
+ ```ts
19
+ import { createAuthClient } from "@tktchurch/auth";
20
+
21
+ const auth = createAuthClient({
22
+ clientId: "your_client_id",
23
+ // Optional:
24
+ // clientSecret: "your_client_secret",
25
+ // baseUrl: "https://prod-auth.tktchurch.com",
26
+ });
27
+
28
+ const tokens = await auth.token.password({
29
+ username: "user@example.com",
30
+ password: "your_password",
31
+ scope: "openid profile email",
32
+ });
33
+
34
+ console.log(tokens.accessToken);
35
+ ```
36
+
37
+ ## Authorization Code + PKCE (redirect flow)
38
+
39
+ The recommended browser/SSR login flow. The SDK generates PKCE, `state`, and
40
+ `nonce` for you and hands back everything you must persist across the redirect —
41
+ no more hand-rolling crypto per app.
42
+
43
+ **1. Start the flow** (server route that begins login):
44
+
45
+ ```ts
46
+ import { createAuthClient } from "@tktchurch/auth";
47
+
48
+ const auth = createAuthClient({ clientId: process.env.TKT_CLIENT_ID! });
49
+
50
+ const request = await auth.authorize.createRequest({
51
+ redirectUri: "https://app.example.com/callback",
52
+ // scope defaults to "openid profile email offline_access"
53
+ });
54
+
55
+ // Persist these in an HttpOnly cookie / server session, keyed by `state`:
56
+ // request.state, request.nonce, request.codeVerifier, request.redirectUri
57
+ // Then redirect the user agent:
58
+ // 302 -> request.url
59
+ ```
60
+
61
+ **2. Handle the callback** — one call validates `state` (constant-time),
62
+ surfaces server errors, and exchanges the code for tokens:
63
+
64
+ ```ts
65
+ const tokens = await auth.authorize.handleCallback({
66
+ callback: requestUrl, // full callback URL or its query string
67
+ expectedState: saved.state, // the state you persisted in step 1
68
+ codeVerifier: saved.codeVerifier,
69
+ redirectUri: saved.redirectUri,
70
+ });
71
+
72
+ // tokens.accessToken / tokens.refreshToken — persist refresh in HttpOnly cookie;
73
+ // keep access token in server memory per request (see examples/).
74
+ ```
75
+
76
+ > Security: the PKCE `codeVerifier` is a secret — keep it server-side (HttpOnly
77
+ > cookie or session store), never in `localStorage`. `state` is verified with a
78
+ > constant-time comparison to defeat CSRF and timing oracles.
79
+
80
+ ### Open-redirect protection
81
+
82
+ Always sanitize any `next`/`returnTo` value before redirecting after login:
83
+
84
+ ```ts
85
+ import { sanitizePostAuthRedirect } from "@tktchurch/auth";
86
+
87
+ return Response.redirect(sanitizePostAuthRedirect(next, "/dashboard"));
88
+ // "//evil.com", "https://evil.com", "javascript:…", CRLF → fallback
89
+ ```
90
+
91
+ ### Low-level PKCE helpers
92
+
93
+ If you need the primitives directly:
94
+
95
+ ```ts
96
+ import { generatePkce, generateState, generateNonce, deriveCodeChallenge } from "@tktchurch/auth";
97
+
98
+ const { codeVerifier, codeChallenge, codeChallengeMethod } = await generatePkce();
99
+ ```
100
+
101
+ ### OIDC discovery
102
+
103
+ ```ts
104
+ const meta = await auth.oidc.discover(); // /.well-known/openid-configuration
105
+ console.log(meta.authorizationEndpoint, meta.tokenEndpoint, meta.jwksUri);
106
+ ```
107
+
108
+ ## Framework-Agnostic Usage
109
+
110
+ ### Server route (recommended)
111
+
112
+ Use in-memory storage (the default) and persist refresh tokens in HttpOnly
113
+ cookies. See [`examples/`](./examples/) for full PKCE redirect flows.
114
+
115
+ ```ts
116
+ import { createAuthClient } from "@tktchurch/auth";
117
+
118
+ const auth = createAuthClient({
119
+ clientId: process.env.TKT_CLIENT_ID!,
120
+ clientSecret: process.env.TKT_CLIENT_SECRET!,
121
+ });
122
+
123
+ export async function GET() {
124
+ const me = await auth.user.me();
125
+ return Response.json(me);
126
+ }
127
+ ```
128
+
129
+ > Do **not** store OAuth tokens in `localStorage` or `sessionStorage`. The SDK
130
+ > does not ship a browser persistence adapter — use server-side cookies or a
131
+ > platform secure store (Keychain, Keystore). See [`SECURITY.md`](./SECURITY.md).
132
+
133
+ ## Framework Examples (Best Practices)
134
+
135
+ Production-oriented examples are available in:
136
+
137
+ - [`examples/next-app-router`](./examples/next-app-router/README.md)
138
+ - [`examples/nuxt3`](./examples/nuxt3/README.md)
139
+
140
+ They follow server-first patterns:
141
+
142
+ 1. Authorization code + PKCE redirect flow (primary).
143
+ 2. `clientSecret` remains server-only.
144
+ 3. Refresh token is stored in `HttpOnly` cookie.
145
+ 4. PKCE `codeVerifier` is stored in a signed HttpOnly session cookie.
146
+ 5. Refresh token rotation is performed on every refresh call.
147
+ 6. Logout revokes refresh token and clears cookies.
148
+
149
+ ## Nuxt Module (`@tktchurch/auth/nuxt`)
150
+
151
+ Register the module in `nuxt.config.ts`:
152
+
153
+ ```ts
154
+ export default defineNuxtConfig({
155
+ modules: ["@tktchurch/auth/nuxt"],
156
+ tktAuth: {
157
+ baseUrl: process.env.TKT_AUTH_BASE_URL ?? "https://prod-auth.tktchurch.com",
158
+ clientId: process.env.TKT_CLIENT_ID,
159
+ clientSecret: process.env.TKT_CLIENT_SECRET,
160
+ autoRefresh: false,
161
+ refreshCookieName: "tkt_refresh_token",
162
+ },
163
+ });
164
+ ```
165
+
166
+ Then use provided imports:
167
+
168
+ ```ts
169
+ const auth = createTktServerAuthClient();
170
+ const appAuth = useTktAuth();
171
+ const refreshCookieName = useTktRefreshCookieName();
172
+ ```
173
+
174
+ ## AuthFlow Example
175
+
176
+ ```ts
177
+ const init = await auth.flow.initAuthentication({
178
+ username: "user@example.com",
179
+ });
180
+
181
+ let status = await auth.flow.executeStep({
182
+ sessionId: init.sessionId,
183
+ stepId: init.currentStep.stepId,
184
+ credential: {
185
+ username: "user@example.com",
186
+ password: "secret",
187
+ },
188
+ });
189
+
190
+ while (status.status === "in_progress") {
191
+ // Render UI for status.nextStep and collect credentials for that step.
192
+ status = await auth.flow.executeStep({
193
+ sessionId: status.sessionId,
194
+ stepId: status.nextStep.stepId,
195
+ credential: {},
196
+ });
197
+ }
198
+
199
+ // status.status === "complete"
200
+ console.log(status.accessToken);
201
+ ```
202
+
203
+ ## Token Storage
204
+
205
+ ### Memory (default)
206
+
207
+ ```ts
208
+ import { createAuthClient, createMemoryTokenStorage } from "@tktchurch/auth";
209
+
210
+ const auth = createAuthClient({
211
+ clientId: "client_id",
212
+ storage: createMemoryTokenStorage(),
213
+ });
214
+ ```
215
+
216
+ ### Custom `TokenStorage`
217
+
218
+ For platform-specific secure backends (Keychain, Keystore, encrypted server
219
+ session), implement `TokenStorage` using the exported validators
220
+ (`assertValidAuthTokens`, `parseStoredAuthTokens`, `serializeAuthTokens`).
221
+ See [`SECURITY.md`](./SECURITY.md).
222
+
223
+ ## Error Handling
224
+
225
+ ```ts
226
+ import { AuthError, MFARequiredAuthError } from "@tktchurch/auth";
227
+
228
+ try {
229
+ await auth.token.password({
230
+ username: "user@example.com",
231
+ password: "secret",
232
+ });
233
+ } catch (error) {
234
+ if (error instanceof MFARequiredAuthError) {
235
+ console.log("MFA required:", error.mfaMethods);
236
+ } else if (error instanceof AuthError) {
237
+ console.log(error.code, error.message, error.status);
238
+ } else {
239
+ throw error;
240
+ }
241
+ }
242
+ ```
243
+
244
+ ## Authenticated Fetch
245
+
246
+ `fetchWithAuth` adds the bearer token automatically and retries once on `401` using refresh token when possible.
247
+
248
+ > **Note:** `fetchWithAuth` and `request()` are available only in the **full** SDK (GitHub Packages / local `file:` build). The public npmjs consumer build omits generic passthrough helpers.
249
+
250
+ ```ts
251
+ const response = await auth.fetchWithAuth("/api/v1/users/me");
252
+ if (!response.ok) {
253
+ // handle response
254
+ }
255
+ ```
256
+
257
+ ## API reference (public consumer build)
258
+
259
+ The public npmjs package ships OAuth/OIDC client namespaces only. Admin console modules (`clients`, `roles`, `auditLogs`, …) and generic passthrough helpers are available in the **full** SDK from GitHub Packages — see [`CONTEXT.md`](./CONTEXT.md).
260
+
261
+ | Namespace | Methods | Auth |
262
+ | --- | --- | --- |
263
+ | `token` | `password`, `refresh`, `clientCredentials`, `authorizationCode`, `tokenExchange`, `revoke`, `introspect` | client credentials / stored tokens |
264
+ | `authorize` | `createRequest`, `parseCallback`, `handleCallback`, `consent`, `consentWithCredentials` | public + server session |
265
+ | `oidc` | `userInfo`, `discover`, `jwks` | bearer / public |
266
+ | `oauth` | `publicClient`, `discoverAuthorizationServer` | public |
267
+ | `flow` | `initAuthentication`, `executeStep`, `initRegistration`, `executeRegistrationStep`, `initRecovery`, `executeRecoveryStep`, `getStatus` | public / step session |
268
+ | `user` | `me`, `updateMe`, `changePassword`, `deleteAvatar`, `verifyPhone`, `securityOverview`, `recoveryContacts.*`, `identities.*`, `deleteMe` | bearer |
269
+ | `sessions` | `list`, `current`, `get`, `update`, `revoke`, `revokeAll`, `revokeAllDevices` | bearer |
270
+ | `webauthn` | `registerBegin/Finish`, `authenticateBegin/Finish`, `credentials`, `removeCredential`, `renameCredential`, `setPrimaryCredential` | bearer / public begin |
271
+ | `passwordReset` | `request`, `validate`, `complete` | public |
272
+ | `mfa` | `setup`, `verify`, `devices`, `removeDevice`, `regenerateBackupCodes`, `disable` | bearer |
273
+ | `maintenance` | `status` | public |
274
+
275
+ Integrators must pass an explicit `baseUrl` in `createAuthClient({ baseUrl, clientId, … })`. The public consumer build does not export `DEFAULT_BASE_URL`.
276
+
277
+ ### Internal admin SDK (GitHub Packages only)
278
+
279
+ The full build adds `consents`, admin `maintenance.*`, `clients` … `comms`, `privacy`, `user.admin.*`, plus `request()` / `fetchWithAuth()`. Admin methods require a bearer access token with matching backend permissions (`client:read`, `user:write`, `*:*`, etc.). The SDK does not enforce permissions — the OAuth server does.
280
+
281
+ ### Migrating from hand-rolled `oauth.ts`
282
+
283
+ Replace direct `fetch` calls with namespaced SDK methods:
284
+
285
+ ```ts
286
+ // Before
287
+ await fetch(`${baseUrl}/oauth/token`, { method: "POST", body });
288
+
289
+ // After
290
+ const tokens = await auth.token.authorizationCode({ code, redirectUri, codeVerifier });
291
+ ```
292
+
293
+ For admin console CRUD (`/api/v1/clients`, etc.), use the **full** SDK from GitHub Packages — see [`CONTEXT.md`](./CONTEXT.md).
294
+
295
+ Inject internal URL rewriting via `createAuthClient({ fetch })` — same pattern as
296
+ `accounts` / `developers` `oauth-fetch.ts`.
297
+
298
+ ## Release and Publish
299
+
300
+ - Changelog: [`CHANGELOG.md`](./CHANGELOG.md)
301
+ - Publishing guide: [`PUBLISHING.md`](./PUBLISHING.md)
302
+
303
+ GitHub Packages (private, `tktchurch` scope) is configured via:
304
+
305
+ - Script: `bun run publish:github`
306
+ - Workflow: [`.github/workflows/publish-github-packages.yml`](./.github/workflows/publish-github-packages.yml)
307
+ - Auth token: `NODE_AUTH_TOKEN` (`GITHUB_TOKEN` in workflow)
308
+
309
+ npmjs (public) publishing ships the **consumer** build only:
310
+
311
+ - Script: `bun run publish:npmjs` (runs `release:check:consumer`)
312
+ - Workflow: [`.github/workflows/publish-npmjs.yml`](./.github/workflows/publish-npmjs.yml)
313
+ - Auth: npm trusted publishing (OIDC, no `NPM_TOKEN` secret) or local `NODE_AUTH_TOKEN`
314
+
315
+ GitHub Packages ships the **full** internal SDK. See [`PUBLISHING.md`](./PUBLISHING.md) for the dual-build matrix.