@seamless-auth/types 0.4.0 → 0.4.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 +16 -0
- package/README.md +121 -63
- package/dist/schemas/webauthn/schema.d.ts +2 -2
- package/package.json +6 -6
- package/src/index.ts +19 -0
- package/src/schemas/admin/schema.ts +54 -0
- package/src/schemas/auth/auth.schema.ts +139 -0
- package/src/schemas/authEvent/schema.ts +120 -0
- package/src/schemas/common/schema.ts +33 -0
- package/src/schemas/credential/schema.ts +103 -0
- package/src/schemas/me/schema.ts +32 -0
- package/src/schemas/messaging/schema.ts +86 -0
- package/src/schemas/metrics/schema.ts +115 -0
- package/src/schemas/oauth/schema.ts +70 -0
- package/src/schemas/organization/schema.ts +135 -0
- package/src/schemas/role/matching.ts +76 -0
- package/src/schemas/role/schema.ts +15 -0
- package/src/schemas/session/schema.ts +26 -0
- package/src/schemas/stepUp/schema.ts +27 -0
- package/src/schemas/systemConfig/schema.ts +196 -0
- package/src/schemas/totp/schema.ts +34 -0
- package/src/schemas/user/schema.ts +75 -0
- package/src/schemas/webauthn/schema.ts +82 -0
- package/src/shared.ts +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @seamless-auth/types
|
|
2
2
|
|
|
3
|
+
## 0.4.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 9ae3092: No contract changes. Schemas, types, and exports are untouched.
|
|
8
|
+
|
|
9
|
+
Packaging: the non-test sources under `src` now ship in the tarball. The published `dist` has
|
|
10
|
+
always included declaration maps and source maps, but the sources they pointed at were not in the
|
|
11
|
+
package, so the maps were dangling. Go to Definition now lands on the actual schema instead of a
|
|
12
|
+
`.d.ts`.
|
|
13
|
+
|
|
14
|
+
Documentation: the README now carries npm, CI, Node, and license badges, a requirements section
|
|
15
|
+
that spells out the module resolution the subpath exports need, a conventions section covering the
|
|
16
|
+
schema and type alias pairing, and sections on versioning, supply chain, and security.
|
|
17
|
+
`SECURITY.md` states which versions are supported and what is in scope for this repository.
|
|
18
|
+
|
|
3
19
|
## 0.4.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,24 +1,35 @@
|
|
|
1
1
|
# @seamless-auth/types
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@seamless-auth/types)
|
|
4
|
+
[](https://github.com/fells-code/seamless-auth-types/actions/workflows/ci.yml)
|
|
5
|
+
[](.nvmrc)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
3
8
|
Shared TypeScript types and Zod schemas for the SeamlessAuth ecosystem.
|
|
4
9
|
|
|
5
|
-
This package
|
|
10
|
+
This package is the single source of truth for the SeamlessAuth domain models (Users,
|
|
11
|
+
Credentials, Sessions, Auth, Auth Events, Organizations) and for the request and response
|
|
12
|
+
contracts built on top of them. Every layer of the stack validates against the same schemas:
|
|
6
13
|
|
|
7
14
|
- API servers
|
|
8
|
-
- SDKs
|
|
15
|
+
- SDKs and server adapters
|
|
9
16
|
- Frontend applications
|
|
10
17
|
- CLI tools
|
|
11
18
|
|
|
12
|
-
|
|
19
|
+
Because everything downstream imports these contracts, a change here is treated as
|
|
20
|
+
breaking by default. See [Versioning and stability](#versioning-and-stability).
|
|
13
21
|
|
|
14
|
-
##
|
|
22
|
+
## Requirements
|
|
15
23
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
24
|
+
| | |
|
|
25
|
+
| -------------------- | ------------------------- |
|
|
26
|
+
| Node | 24 (`>=24 <25`) |
|
|
27
|
+
| TypeScript | 5.x |
|
|
28
|
+
| Runtime dependencies | `zod@^4` and nothing else |
|
|
20
29
|
|
|
21
|
-
|
|
30
|
+
The package ships as ESM only. The root import works under any module resolution, but the
|
|
31
|
+
[subpath exports](#subpath-exports) are resolved from `package.json` `exports`, so consumers
|
|
32
|
+
that use them need `moduleResolution` set to `node16`, `nodenext`, or `bundler`.
|
|
22
33
|
|
|
23
34
|
## Installation
|
|
24
35
|
|
|
@@ -26,24 +37,47 @@ This package provides a single source of truth for domain models like Users, Cre
|
|
|
26
37
|
npm install @seamless-auth/types
|
|
27
38
|
```
|
|
28
39
|
|
|
29
|
-
|
|
40
|
+
## Quick start
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { UserSchema, type User } from '@seamless-auth/types';
|
|
44
|
+
|
|
45
|
+
// Validate untrusted input and get a fully typed value back.
|
|
46
|
+
const user: User = UserSchema.parse(await response.json());
|
|
47
|
+
```
|
|
30
48
|
|
|
31
49
|
## Usage
|
|
32
50
|
|
|
33
|
-
###
|
|
51
|
+
### Validate data
|
|
52
|
+
|
|
53
|
+
Every model is a Zod schema, so you get runtime validation and the static type from one
|
|
54
|
+
declaration:
|
|
34
55
|
|
|
35
56
|
```ts
|
|
36
|
-
import {
|
|
57
|
+
import { LoginRequestSchema } from '@seamless-auth/types';
|
|
58
|
+
|
|
59
|
+
const parsed = LoginRequestSchema.safeParse(req.body);
|
|
60
|
+
if (!parsed.success) {
|
|
61
|
+
return res.status(400).json({ error: parsed.error.issues });
|
|
62
|
+
}
|
|
37
63
|
```
|
|
38
64
|
|
|
39
|
-
###
|
|
65
|
+
### Infer types
|
|
40
66
|
|
|
41
67
|
```ts
|
|
42
|
-
|
|
68
|
+
import type { User } from '@seamless-auth/types';
|
|
69
|
+
|
|
70
|
+
function handleUser(user: User) {
|
|
71
|
+
console.log(user.email);
|
|
72
|
+
}
|
|
43
73
|
```
|
|
44
74
|
|
|
45
|
-
|
|
46
|
-
|
|
75
|
+
### Roles
|
|
76
|
+
|
|
77
|
+
Role schemas accept plain roles such as `admin` and colon-separated scoped roles such as
|
|
78
|
+
`admin:read` and `admin:write`. Whitespace, underscores, slashes, and backslashes are
|
|
79
|
+
rejected, so a role name is always safe to embed in a JWT claim, a URL path segment, or a
|
|
80
|
+
config file without escaping.
|
|
47
81
|
|
|
48
82
|
### Match roles without Zod
|
|
49
83
|
|
|
@@ -62,22 +96,10 @@ if (!hasScopedRole(user.roles, 'billing:invoices:read')) {
|
|
|
62
96
|
`@seamless-auth/types/role` adds `RoleNameSchema` on top of the same matchers, and the package
|
|
63
97
|
root still exports all of them, so existing imports keep working.
|
|
64
98
|
|
|
65
|
-
### Infer types
|
|
66
|
-
|
|
67
|
-
```ts
|
|
68
|
-
import type { User } from '@seamless-auth/types';
|
|
69
|
-
|
|
70
|
-
function handleUser(user: User) {
|
|
71
|
-
console.log(user.email);
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
---
|
|
76
|
-
|
|
77
99
|
## Modules
|
|
78
100
|
|
|
79
|
-
Every module is re-exported from the package root, so import from
|
|
80
|
-
|
|
101
|
+
Every module is re-exported from the package root, so import from `@seamless-auth/types`
|
|
102
|
+
unless one of the subpath exports below fits better.
|
|
81
103
|
|
|
82
104
|
| Module | Covers |
|
|
83
105
|
| -------------- | ------------------------------------------------------------------- |
|
|
@@ -106,69 +128,105 @@ Every module is re-exported from the package root, so import from
|
|
|
106
128
|
| `@seamless-auth/types/role` | Role name schema plus the matchers |
|
|
107
129
|
| `@seamless-auth/types/role/matching` | The matchers alone, with no Zod import |
|
|
108
130
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
## Zod as the Source of Truth
|
|
131
|
+
## Conventions
|
|
112
132
|
|
|
113
|
-
|
|
133
|
+
**Zod is the source of truth.** Models are declared as schemas and the TypeScript type is
|
|
134
|
+
inferred from the schema. No type in this package is hand-written alongside a schema that
|
|
135
|
+
already describes it:
|
|
114
136
|
|
|
115
137
|
```ts
|
|
116
138
|
export const UserSchema = z.object({
|
|
117
|
-
id: z.
|
|
118
|
-
email: z.
|
|
139
|
+
id: z.uuid(),
|
|
140
|
+
email: z.email(),
|
|
119
141
|
});
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
Types are inferred:
|
|
123
142
|
|
|
124
|
-
```ts
|
|
125
143
|
export type User = z.infer<typeof UserSchema>;
|
|
126
144
|
```
|
|
127
145
|
|
|
128
|
-
|
|
146
|
+
**Every exported schema has a matching type alias.** `XSchema` is always paired with `X`, so
|
|
147
|
+
you never have to write `z.infer<typeof XSchema>` at a call site. This is enforced by a test,
|
|
148
|
+
not by convention alone.
|
|
149
|
+
|
|
150
|
+
**Framework-agnostic.** No server, browser, or Node-only APIs, and no runtime dependency
|
|
151
|
+
beyond Zod, so the same contracts load in an API process, a browser bundle, and a CLI.
|
|
152
|
+
|
|
153
|
+
**Strict typing throughout.** No `any` and no non-null assertions. Wire-facing schemas are
|
|
154
|
+
`.strict()` where unknown keys should be rejected rather than silently dropped.
|
|
129
155
|
|
|
130
|
-
## Versioning
|
|
156
|
+
## Versioning and stability
|
|
131
157
|
|
|
132
158
|
This package follows semantic versioning:
|
|
133
159
|
|
|
134
|
-
- PATCH for fixes and
|
|
135
|
-
- MINOR for additive changes such as new
|
|
136
|
-
- MAJOR for breaking changes such as
|
|
160
|
+
- **PATCH** for fixes with no effect on the contract, including docs and internal tidying
|
|
161
|
+
- **MINOR** for additive changes such as a new module, export, or optional field
|
|
162
|
+
- **MAJOR** for breaking changes such as a removed or renamed export, a field whose type
|
|
163
|
+
changes, or a schema that now rejects input it used to accept
|
|
164
|
+
|
|
165
|
+
A widening change (a wider enum, a field that becomes nullable) is not breaking at runtime,
|
|
166
|
+
but it does change the inferred TypeScript type, so it is called out in the release notes.
|
|
167
|
+
|
|
168
|
+
Releases are managed with [Changesets](https://github.com/changesets/changesets). See
|
|
169
|
+
[RELEASES.md](RELEASES.md) for the release flow and [CHANGELOG.md](CHANGELOG.md) for the
|
|
170
|
+
history.
|
|
137
171
|
|
|
138
|
-
|
|
172
|
+
## Supply chain
|
|
173
|
+
|
|
174
|
+
- Published from CI only, from a tagged release on `main`, never from a developer machine.
|
|
175
|
+
- Every release carries [npm provenance](https://docs.npmjs.com/generating-provenance-statements),
|
|
176
|
+
so the published tarball is cryptographically linked to the commit and workflow that built it.
|
|
177
|
+
- One runtime dependency (`zod`). Dependency updates are automated and reviewed like any other
|
|
178
|
+
change.
|
|
179
|
+
- The published tarball is limited to `dist`, the non-test sources under `src`, `README.md`,
|
|
180
|
+
`CHANGELOG.md`, `LICENSE`, and `package.json`. `npm run check-npm-build` prints the contents in
|
|
181
|
+
CI on every push and release.
|
|
182
|
+
- Sources ship alongside the declaration maps and source maps, so Go to Definition in your editor
|
|
183
|
+
lands on the actual schema rather than a `.d.ts`.
|
|
184
|
+
|
|
185
|
+
## Security
|
|
186
|
+
|
|
187
|
+
Do not open a public issue for a vulnerability. Report it privately to
|
|
188
|
+
**security@seamlessauth.com**. See [SECURITY.md](SECURITY.md) for what to include, our
|
|
189
|
+
acknowledgement window, and the coordinated disclosure process.
|
|
139
190
|
|
|
140
191
|
## Development
|
|
141
192
|
|
|
142
193
|
```bash
|
|
143
|
-
#
|
|
144
|
-
npm
|
|
194
|
+
nvm use # Node 24, pinned by .nvmrc
|
|
195
|
+
npm ci
|
|
145
196
|
|
|
146
|
-
#
|
|
147
|
-
npm run dev
|
|
148
|
-
|
|
149
|
-
# type check
|
|
197
|
+
npm run build # compile to dist/
|
|
198
|
+
npm run dev # tsc --watch
|
|
150
199
|
npm run typecheck
|
|
200
|
+
npm run lint
|
|
201
|
+
npm run format:check
|
|
202
|
+
npm test
|
|
151
203
|
```
|
|
152
204
|
|
|
153
205
|
## Contributing
|
|
154
206
|
|
|
155
|
-
Contributions are welcome.
|
|
207
|
+
Contributions are welcome. Start with the organization
|
|
208
|
+
[contributing guide](https://github.com/fells-code/.github/blob/main/CONTRIBUTING.md) and the
|
|
209
|
+
[repository standards](https://github.com/fells-code/.github/blob/main/REPO-STANDARDS.md).
|
|
210
|
+
[AGENTS.md](AGENTS.md) documents the repository layout and the working standards in more detail.
|
|
156
211
|
|
|
157
|
-
|
|
212
|
+
For a change in this repository specifically:
|
|
158
213
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
214
|
+
1. Add or change the schema under `src/schemas/<model>/`.
|
|
215
|
+
2. Export it from `src/index.ts` if it is part of the public API.
|
|
216
|
+
3. Run `npm run typecheck`, `npm run lint`, `npm run format:check`, `npm test`, and `npm run build`.
|
|
217
|
+
4. Run `npm run changeset` and write the notes for the repositories that consume these
|
|
218
|
+
contracts, not for the implementation. A change to `src/` without a changeset ships nothing.
|
|
162
219
|
|
|
163
|
-
|
|
220
|
+
Keep schemas Zod-based, keep the package framework-agnostic, and treat any change to an
|
|
221
|
+
existing schema as breaking until you can argue otherwise.
|
|
164
222
|
|
|
165
223
|
## License
|
|
166
224
|
|
|
167
|
-
AGPL-3.0 © Fells Code, LLC
|
|
168
|
-
|
|
169
|
-
---
|
|
225
|
+
[AGPL-3.0-only](LICENSE) © Fells Code, LLC
|
|
170
226
|
|
|
171
227
|
## Links
|
|
172
228
|
|
|
173
|
-
-
|
|
174
|
-
-
|
|
229
|
+
- [npm package](https://www.npmjs.com/package/@seamless-auth/types)
|
|
230
|
+
- [GitHub repository](https://github.com/fells-code/seamless-auth-types)
|
|
231
|
+
- [SeamlessAuth](https://seamlessauth.com)
|
|
232
|
+
- [Fells Code](https://github.com/fells-code)
|
|
@@ -9,8 +9,8 @@ export declare const WebAuthnPrfRequestSchema: z.ZodObject<{
|
|
|
9
9
|
}, z.core.$strip>;
|
|
10
10
|
export type WebAuthnPrfRequest = z.infer<typeof WebAuthnPrfRequestSchema>;
|
|
11
11
|
export declare const WebAuthnRegisterStartQuerySchema: z.ZodObject<{
|
|
12
|
-
requestPrf: z.
|
|
13
|
-
requirePrf: z.
|
|
12
|
+
requestPrf: z.ZodPreprocess<z.ZodOptional<z.ZodBoolean>>;
|
|
13
|
+
requirePrf: z.ZodPreprocess<z.ZodOptional<z.ZodBoolean>>;
|
|
14
14
|
}, z.core.$strip>;
|
|
15
15
|
export type WebAuthnRegisterStartQuery = z.infer<typeof WebAuthnRegisterStartQuerySchema>;
|
|
16
16
|
export declare const WebAuthnAssertionStartSchema: z.ZodDefault<z.ZodObject<{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seamless-auth/types",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Shared TypeScript types and Zod schemas for SeamlessAuth.",
|
|
5
5
|
"author": "Fells Code, LLC",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -24,6 +24,8 @@
|
|
|
24
24
|
"sideEffects": false,
|
|
25
25
|
"files": [
|
|
26
26
|
"dist",
|
|
27
|
+
"src",
|
|
28
|
+
"!src/**/*.test.ts",
|
|
27
29
|
"README.md",
|
|
28
30
|
"CHANGELOG.md",
|
|
29
31
|
"LICENSE"
|
|
@@ -58,7 +60,6 @@
|
|
|
58
60
|
"prepublishOnly": "npm run build",
|
|
59
61
|
"test": "vitest run",
|
|
60
62
|
"test:watch": "vitest",
|
|
61
|
-
"coverage": "vitest run --coverage",
|
|
62
63
|
"changeset": "changeset",
|
|
63
64
|
"version-packages": "changeset version",
|
|
64
65
|
"release:stable": "npm run build && changeset publish",
|
|
@@ -78,15 +79,14 @@
|
|
|
78
79
|
},
|
|
79
80
|
"devDependencies": {
|
|
80
81
|
"@changesets/cli": "^2.31.1",
|
|
81
|
-
"@commitlint/cli": "^
|
|
82
|
-
"@commitlint/config-conventional": "^
|
|
82
|
+
"@commitlint/cli": "^21.2.1",
|
|
83
|
+
"@commitlint/config-conventional": "^21.2.0",
|
|
83
84
|
"@typescript-eslint/eslint-plugin": "^8.57.2",
|
|
84
85
|
"@typescript-eslint/parser": "^8.57.2",
|
|
85
|
-
"@vitest/coverage-v8": "^4.1.10",
|
|
86
86
|
"eslint": "^10.1.0",
|
|
87
87
|
"eslint-config-prettier": "^10.1.8",
|
|
88
88
|
"husky": "^9.1.7",
|
|
89
|
-
"lint-staged": "^
|
|
89
|
+
"lint-staged": "^17.2.0",
|
|
90
90
|
"prettier": "^3.8.1",
|
|
91
91
|
"typescript": "^5.9.3",
|
|
92
92
|
"vitest": "^4.1.1"
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export * from './shared.js';
|
|
2
|
+
|
|
3
|
+
export * from './schemas/common/schema.js';
|
|
4
|
+
export * from './schemas/role/schema.js';
|
|
5
|
+
export * from './schemas/user/schema.js';
|
|
6
|
+
export * from './schemas/credential/schema.js';
|
|
7
|
+
export * from './schemas/session/schema.js';
|
|
8
|
+
export * from './schemas/authEvent/schema.js';
|
|
9
|
+
export * from './schemas/messaging/schema.js';
|
|
10
|
+
export * from './schemas/systemConfig/schema.js';
|
|
11
|
+
export * from './schemas/auth/auth.schema.js';
|
|
12
|
+
export * from './schemas/oauth/schema.js';
|
|
13
|
+
export * from './schemas/webauthn/schema.js';
|
|
14
|
+
export * from './schemas/totp/schema.js';
|
|
15
|
+
export * from './schemas/stepUp/schema.js';
|
|
16
|
+
export * from './schemas/organization/schema.js';
|
|
17
|
+
export * from './schemas/me/schema.js';
|
|
18
|
+
export * from './schemas/metrics/schema.js';
|
|
19
|
+
export * from './schemas/admin/schema.js';
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { AuthEventSchema } from '../authEvent/schema.js';
|
|
3
|
+
import { CredentialResponseSchema } from '../credential/schema.js';
|
|
4
|
+
import { SessionSchema } from '../session/schema.js';
|
|
5
|
+
import { ApiUserSchema } from '../user/schema.js';
|
|
6
|
+
|
|
7
|
+
export const UserIdParamSchema = z.object({
|
|
8
|
+
userId: z.string(),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export type UserIdParam = z.infer<typeof UserIdParamSchema>;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* What an operator clears when a user replaces a lost device. Each step is
|
|
15
|
+
* opt-out rather than opt-in so a hurried recovery does not leave the old
|
|
16
|
+
* device's credentials in place.
|
|
17
|
+
*/
|
|
18
|
+
export const DeviceReplacementRecoverySchema = z
|
|
19
|
+
.object({
|
|
20
|
+
revokeSessions: z.boolean().default(true),
|
|
21
|
+
removePasskeys: z.boolean().default(true),
|
|
22
|
+
disableTotp: z.boolean().default(true),
|
|
23
|
+
})
|
|
24
|
+
.strict();
|
|
25
|
+
|
|
26
|
+
export type DeviceReplacementRecoveryRequest = z.infer<typeof DeviceReplacementRecoverySchema>;
|
|
27
|
+
|
|
28
|
+
export const DeviceReplacementRecoveryResponseSchema = z.object({
|
|
29
|
+
userId: z.string(),
|
|
30
|
+
revokedSessions: z.number().int().nonnegative(),
|
|
31
|
+
removedCredentials: z.number().int().nonnegative(),
|
|
32
|
+
disabledTotpCredentials: z.number().int().nonnegative(),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export type DeviceReplacementRecoveryResponse = z.infer<
|
|
36
|
+
typeof DeviceReplacementRecoveryResponseSchema
|
|
37
|
+
>;
|
|
38
|
+
|
|
39
|
+
export const AdminUserDetailResponseSchema = z.object({
|
|
40
|
+
user: ApiUserSchema,
|
|
41
|
+
sessions: z.array(SessionSchema),
|
|
42
|
+
credentials: z.array(CredentialResponseSchema),
|
|
43
|
+
events: z.array(AuthEventSchema),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export type AdminUserDetailResponse = z.infer<typeof AdminUserDetailResponseSchema>;
|
|
47
|
+
|
|
48
|
+
export const AdminUserAnomaliesResponseSchema = z.object({
|
|
49
|
+
suspiciousEvents: z.array(AuthEventSchema),
|
|
50
|
+
relatedIps: z.array(z.string()),
|
|
51
|
+
relatedAgents: z.array(z.string()),
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export type AdminUserAnomaliesResponse = z.infer<typeof AdminUserAnomaliesResponseSchema>;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
import { AuthDeliverySchema } from '../messaging/schema.js';
|
|
3
|
+
import { LoginMethodSchema } from '../systemConfig/schema.js';
|
|
4
|
+
|
|
5
|
+
export const IdentifierTypeSchema = z.enum(['email', 'phone']);
|
|
6
|
+
|
|
7
|
+
export type IdentifierType = z.infer<typeof IdentifierTypeSchema>;
|
|
8
|
+
|
|
9
|
+
export const LoginRequestSchema = z.object({
|
|
10
|
+
identifier: z.string(),
|
|
11
|
+
passkeyAvailable: z.boolean().optional(),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export type LoginRequest = z.infer<typeof LoginRequestSchema>;
|
|
15
|
+
|
|
16
|
+
export const LoginSuccessResponseSchema = z.object({
|
|
17
|
+
message: z.string(),
|
|
18
|
+
token: z.string().optional(),
|
|
19
|
+
sub: z.string().optional(),
|
|
20
|
+
identifierType: IdentifierTypeSchema.optional(),
|
|
21
|
+
loginMethods: z.array(LoginMethodSchema).optional(),
|
|
22
|
+
ttl: z.number().optional(),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export type LoginSuccessResponse = z.infer<typeof LoginSuccessResponseSchema>;
|
|
26
|
+
|
|
27
|
+
export const RefreshTokenRequestSchema = z.object({});
|
|
28
|
+
|
|
29
|
+
export type RefreshTokenRequest = z.infer<typeof RefreshTokenRequestSchema>;
|
|
30
|
+
|
|
31
|
+
/** @deprecated Use {@link RefreshTokenRequestSchema}. */
|
|
32
|
+
export const RefreshRequestSchema = RefreshTokenRequestSchema;
|
|
33
|
+
|
|
34
|
+
/** @deprecated Use {@link RefreshTokenRequest}. */
|
|
35
|
+
export type RefreshRequest = z.infer<typeof RefreshRequestSchema>;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The token envelope every completed authentication returns, whatever the
|
|
39
|
+
* method. `sessionId` is only present where the flow names the session it
|
|
40
|
+
* created; OTP, magic link, and OAuth completions omit it.
|
|
41
|
+
*/
|
|
42
|
+
export const RefreshSuccessResponseSchema = z.object({
|
|
43
|
+
message: z.string(),
|
|
44
|
+
token: z.string().optional(),
|
|
45
|
+
refreshToken: z.string().optional(),
|
|
46
|
+
sub: z.string().optional(),
|
|
47
|
+
sessionId: z.string().optional(),
|
|
48
|
+
organizationId: z.string().nullable().optional(),
|
|
49
|
+
roles: z.array(z.string()).optional(),
|
|
50
|
+
email: z.string().optional(),
|
|
51
|
+
phone: z.string().nullable().optional(),
|
|
52
|
+
ttl: z.number().optional(),
|
|
53
|
+
refreshTtl: z.number().optional(),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export type RefreshSuccessResponse = z.infer<typeof RefreshSuccessResponseSchema>;
|
|
57
|
+
|
|
58
|
+
export const LogoutScopeSchema = z.enum(['current_session', 'all_sessions']);
|
|
59
|
+
|
|
60
|
+
export type LogoutScope = z.infer<typeof LogoutScopeSchema>;
|
|
61
|
+
|
|
62
|
+
export const RegistrationRequestSchema = z.object({
|
|
63
|
+
email: z.email(),
|
|
64
|
+
// Registration only needs an email. A phone can be added and verified later.
|
|
65
|
+
phone: z.string().nullish(),
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export type RegistrationRequest = z.infer<typeof RegistrationRequestSchema>;
|
|
69
|
+
|
|
70
|
+
export const RegistrationSuccessSchema = z.object({
|
|
71
|
+
message: z.string(),
|
|
72
|
+
sub: z.string().optional(),
|
|
73
|
+
token: z.string().optional(),
|
|
74
|
+
ttl: z.string().optional(),
|
|
75
|
+
delivery: AuthDeliverySchema.optional(),
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
export type RegistrationSuccessResponse = z.infer<typeof RegistrationSuccessSchema>;
|
|
79
|
+
|
|
80
|
+
export const RegisterPhoneRequestSchema = z.object({
|
|
81
|
+
phone: z.string(),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
export type RegisterPhoneRequest = z.infer<typeof RegisterPhoneRequestSchema>;
|
|
85
|
+
|
|
86
|
+
export const RegisterPhoneSuccessSchema = z.object({
|
|
87
|
+
message: z.string(),
|
|
88
|
+
phone: z.string(),
|
|
89
|
+
delivery: AuthDeliverySchema.optional(),
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
export type RegisterPhoneSuccess = z.infer<typeof RegisterPhoneSuccessSchema>;
|
|
93
|
+
|
|
94
|
+
export const VerifyOTPRequestSchema = z.object({
|
|
95
|
+
verificationToken: z.string(),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
export type VerifyOTPRequest = z.infer<typeof VerifyOTPRequestSchema>;
|
|
99
|
+
|
|
100
|
+
export const OTPVerifyTokenSuccessSchema = RefreshSuccessResponseSchema.omit({
|
|
101
|
+
sessionId: true,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
export type OTPVerifyTokenSuccess = z.infer<typeof OTPVerifyTokenSuccessSchema>;
|
|
105
|
+
|
|
106
|
+
export const MagicLinkVerifyParamsSchema = z.object({
|
|
107
|
+
token: z.string(),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
export type MagicLinkVerifyParams = z.infer<typeof MagicLinkVerifyParamsSchema>;
|
|
111
|
+
|
|
112
|
+
export const MagicLinkPollSuccessSchema = RefreshSuccessResponseSchema.omit({
|
|
113
|
+
sessionId: true,
|
|
114
|
+
organizationId: true,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
export type MagicLinkPollSuccess = z.infer<typeof MagicLinkPollSuccessSchema>;
|
|
118
|
+
|
|
119
|
+
/** Body for endpoints that acknowledge a request and may hand back a delivery. */
|
|
120
|
+
export const AuthMessageResponseSchema = z.object({
|
|
121
|
+
message: z.string(),
|
|
122
|
+
token: z.string().optional(),
|
|
123
|
+
delivery: AuthDeliverySchema.optional(),
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
export type AuthMessageResponse = z.infer<typeof AuthMessageResponseSchema>;
|
|
127
|
+
|
|
128
|
+
/** The access token's claims, as a resource server reads them off a request. */
|
|
129
|
+
export const SeamlessAuthUserSchema = z.object({
|
|
130
|
+
id: z.string(),
|
|
131
|
+
roles: z.array(z.string()),
|
|
132
|
+
email: z.string().optional(),
|
|
133
|
+
phone: z.string().nullable().optional(),
|
|
134
|
+
iat: z.number().optional(),
|
|
135
|
+
exp: z.number().optional(),
|
|
136
|
+
token: z.string().optional(),
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
export type SeamlessAuthUser = z.infer<typeof SeamlessAuthUserSchema>;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
import { IsoDate } from '../../shared.js';
|
|
3
|
+
|
|
4
|
+
export const AUTH_EVENT_TYPES = [
|
|
5
|
+
'admin_device_replacement_recovery',
|
|
6
|
+
'admin_session_revoked',
|
|
7
|
+
'auth_action_incremented',
|
|
8
|
+
'bearer_token_failed',
|
|
9
|
+
'bearer_token_success',
|
|
10
|
+
'bearer_token_suspicious',
|
|
11
|
+
'credentials_deleted',
|
|
12
|
+
'informational',
|
|
13
|
+
'internal_user_updated_by_owner',
|
|
14
|
+
'jwks_failed',
|
|
15
|
+
'jwks_success',
|
|
16
|
+
'jwks_suspicious',
|
|
17
|
+
'login_challenge',
|
|
18
|
+
'login_failed',
|
|
19
|
+
'login_success',
|
|
20
|
+
'login_suspicious',
|
|
21
|
+
'logout_failed',
|
|
22
|
+
'logout_success',
|
|
23
|
+
'logout_suspicious',
|
|
24
|
+
'magic_link_failed',
|
|
25
|
+
'magic_link_poll_completed_successfully',
|
|
26
|
+
'magic_link_requested',
|
|
27
|
+
'magic_link_success',
|
|
28
|
+
'mfa_otp_failed',
|
|
29
|
+
'mfa_otp_success',
|
|
30
|
+
'mfa_otp_suspicious',
|
|
31
|
+
'notification_sent',
|
|
32
|
+
'oauth_login_failed',
|
|
33
|
+
'oauth_login_started',
|
|
34
|
+
'oauth_login_success',
|
|
35
|
+
'otp_failed',
|
|
36
|
+
'otp_success',
|
|
37
|
+
'otp_suspicious',
|
|
38
|
+
'recovery_otp_failed',
|
|
39
|
+
'recovery_otp_success',
|
|
40
|
+
'recovery_otp_suspicious',
|
|
41
|
+
'refresh_token_failed',
|
|
42
|
+
'refresh_token_success',
|
|
43
|
+
'refresh_token_suspicious',
|
|
44
|
+
'registration_failed',
|
|
45
|
+
'registration_success',
|
|
46
|
+
'registration_suspicious',
|
|
47
|
+
'request_suspicious',
|
|
48
|
+
'service_token_failed',
|
|
49
|
+
'service_token_rotated',
|
|
50
|
+
'service_token_success',
|
|
51
|
+
'service_token_suspicious',
|
|
52
|
+
'step_up_challenge',
|
|
53
|
+
'step_up_failed',
|
|
54
|
+
'step_up_success',
|
|
55
|
+
'step_up_suspicious',
|
|
56
|
+
'system_config_error',
|
|
57
|
+
'system_config_read',
|
|
58
|
+
'system_config_updated',
|
|
59
|
+
'totp_disabled',
|
|
60
|
+
'totp_enrollment_started',
|
|
61
|
+
'totp_enrollment_success',
|
|
62
|
+
'totp_failed',
|
|
63
|
+
'totp_success',
|
|
64
|
+
'totp_suspicious',
|
|
65
|
+
'user_created',
|
|
66
|
+
'user_data_failed',
|
|
67
|
+
'user_data_success',
|
|
68
|
+
'user_data_suspicious',
|
|
69
|
+
'user_deleted',
|
|
70
|
+
'verify_otp_failed',
|
|
71
|
+
'verify_otp_success',
|
|
72
|
+
'verify_otp_suspicious',
|
|
73
|
+
'webauthn_login_failed',
|
|
74
|
+
'webauthn_login_success',
|
|
75
|
+
'webauthn_login_suspicious',
|
|
76
|
+
'webauthn_registration_failed',
|
|
77
|
+
'webauthn_registration_success',
|
|
78
|
+
'webauthn_registration_suspicious',
|
|
79
|
+
] as const;
|
|
80
|
+
|
|
81
|
+
export const AuthEventTypeEnum = z.enum(AUTH_EVENT_TYPES);
|
|
82
|
+
|
|
83
|
+
export type AuthEventType = z.infer<typeof AuthEventTypeEnum>;
|
|
84
|
+
|
|
85
|
+
// `type` stays a plain string: a stored event written by a newer server must
|
|
86
|
+
// still parse on an older consumer. Use AuthEventTypeEnum to validate input.
|
|
87
|
+
export const AuthEventSchema = z.object({
|
|
88
|
+
id: z.string(),
|
|
89
|
+
user_id: z.string().nullable().optional(),
|
|
90
|
+
type: z.string(),
|
|
91
|
+
ip_address: z.string().nullable().optional(),
|
|
92
|
+
user_agent: z.string().nullable().optional(),
|
|
93
|
+
metadata: z.record(z.string(), z.unknown()).nullable(),
|
|
94
|
+
created_at: IsoDate,
|
|
95
|
+
updated_at: IsoDate,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
export type AuthEvent = z.infer<typeof AuthEventSchema>;
|
|
99
|
+
|
|
100
|
+
export const AuthEventQuerySchema = z.object({
|
|
101
|
+
limit: z.coerce.number().min(1).max(100).default(10),
|
|
102
|
+
offset: z.coerce.number().min(0).default(0),
|
|
103
|
+
|
|
104
|
+
userId: z.string().optional(),
|
|
105
|
+
type: z
|
|
106
|
+
.union([AuthEventTypeEnum, z.string(), z.array(z.union([AuthEventTypeEnum, z.string()]))])
|
|
107
|
+
.optional(),
|
|
108
|
+
|
|
109
|
+
from: z.string().optional(),
|
|
110
|
+
to: z.string().optional(),
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
export type AuthEventQuery = z.infer<typeof AuthEventQuerySchema>;
|
|
114
|
+
|
|
115
|
+
export const AuthEventsResponseSchema = z.object({
|
|
116
|
+
events: z.array(AuthEventSchema),
|
|
117
|
+
total: z.number(),
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
export type AuthEventsResponse = z.infer<typeof AuthEventsResponseSchema>;
|