@nxgt/janus 0.11.0 → 0.12.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 +101 -15
- package/dist/auth/config/janus-config.d.ts +2 -0
- package/dist/auth/config/janus-config.d.ts.map +1 -1
- package/dist/auth/config/resolved-config.d.ts +1 -0
- package/dist/auth/config/resolved-config.d.ts.map +1 -1
- package/dist/auth/index.d.ts +2 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/port/assert-stores.d.ts.map +1 -1
- package/dist/auth/port/memory/sessions.d.ts.map +1 -1
- package/dist/auth/port/types/sessions.d.ts +16 -1
- package/dist/auth/port/types/sessions.d.ts.map +1 -1
- package/dist/auth/port/types/tokens.d.ts +7 -2
- package/dist/auth/port/types/tokens.d.ts.map +1 -1
- package/dist/auth/second-factor/{regenerate-attempts.d.ts → app-code-attempts.d.ts} +13 -10
- package/dist/auth/second-factor/app-code-attempts.d.ts.map +1 -0
- package/dist/auth/sessions/authenticate.d.ts.map +1 -1
- package/dist/auth/sessions/fresh.d.ts +26 -0
- package/dist/auth/sessions/fresh.d.ts.map +1 -0
- package/dist/auth/sessions/standing.d.ts +20 -0
- package/dist/auth/sessions/standing.d.ts.map +1 -0
- package/dist/auth/step-up/codes.d.ts +29 -0
- package/dist/auth/step-up/codes.d.ts.map +1 -0
- package/dist/auth/step-up/flows.d.ts +19 -0
- package/dist/auth/step-up/flows.d.ts.map +1 -0
- package/dist/auth/step-up/open.d.ts +23 -0
- package/dist/auth/step-up/open.d.ts.map +1 -0
- package/dist/auth/step-up/request.d.ts +12 -0
- package/dist/auth/step-up/request.d.ts.map +1 -0
- package/dist/auth/types/index.d.ts +1 -0
- package/dist/auth/types/index.d.ts.map +1 -1
- package/dist/auth/types/janus.d.ts +2 -1
- package/dist/auth/types/janus.d.ts.map +1 -1
- package/dist/auth/types/step-up.d.ts +79 -0
- package/dist/auth/types/step-up.d.ts.map +1 -0
- package/dist/auth/users/any-type-api.d.ts +2 -2
- package/dist/auth/users/any-type-api.d.ts.map +1 -1
- package/dist/auth/users/type-api.d.ts +1 -1
- package/dist/auth/users/type-api.d.ts.map +1 -1
- package/dist/chunks/{index-5e2fw7he.js → index-j2gd8fry.js} +12 -3
- package/dist/chunks/{index-5e2fw7he.js.map → index-j2gd8fry.js.map} +4 -4
- package/dist/chunks/{index-5tm04t5p.js → index-jp2kka6d.js} +2 -2
- package/dist/chunks/{index-6f6wja93.js → index-km7ffctx.js} +2 -2
- package/dist/chunks/{index-4m49cye4.js → index-rd2rddvv.js} +15 -12
- package/dist/chunks/{index-4m49cye4.js.map → index-rd2rddvv.js.map} +3 -3
- package/dist/conformance/cases/outage.d.ts.map +1 -1
- package/dist/conformance/cases/sessions/index.d.ts.map +1 -1
- package/dist/conformance/cases/sessions/reauthentication.d.ts +4 -0
- package/dist/conformance/cases/sessions/reauthentication.d.ts.map +1 -0
- package/dist/conformance/cases/tokens/index.d.ts.map +1 -1
- package/dist/conformance/cases/tokens/kinds.d.ts +4 -0
- package/dist/conformance/cases/tokens/kinds.d.ts.map +1 -0
- package/dist/conformance/index.js +147 -60
- package/dist/conformance/index.js.map +8 -6
- package/dist/errors/janus-error/codes.d.ts +7 -0
- package/dist/errors/janus-error/codes.d.ts.map +1 -1
- package/dist/errors/janus-error/index.d.ts +1 -1
- package/dist/errors/janus-error/index.d.ts.map +1 -1
- package/dist/errors/janus-error/refusals.d.ts +8 -0
- package/dist/errors/janus-error/refusals.d.ts.map +1 -1
- package/dist/errors/janus-error/status.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +175 -18
- package/dist/index.js.map +16 -10
- package/dist/permissions/index.js +3 -3
- package/docs/README.md +1 -0
- package/docs/guide/adapters.md +38 -4
- package/docs/guide/errors.md +1 -0
- package/docs/guide/second-factor.md +22 -16
- package/docs/guide/sessions.md +7 -0
- package/docs/guide/step-up.md +178 -0
- package/docs/guide/users.md +1 -0
- package/docs/guide/vocabulary.md +3 -2
- package/docs/roadmap.md +12 -16
- package/docs/troubleshooting.md +182 -7
- package/package.json +1 -1
- package/dist/auth/second-factor/regenerate-attempts.d.ts.map +0 -1
- /package/dist/chunks/{index-5tm04t5p.js.map → index-jp2kka6d.js.map} +0 -0
- /package/dist/chunks/{index-6f6wja93.js.map → index-km7ffctx.js.map} +0 -0
package/README.md
CHANGED
|
@@ -165,7 +165,7 @@ async function signIn(email: string, password: string): Promise<Response> {
|
|
|
165
165
|
```
|
|
166
166
|
|
|
167
167
|
`JanusError` is the base of everything thrown at call time. It extends `Error`,
|
|
168
|
-
so no consumer has to order their `catch` blocks. `code` is a union of
|
|
168
|
+
so no consumer has to order their `catch` blocks. `code` is a union of twenty
|
|
169
169
|
string literals, so a `switch` over it is exhaustive and adding a code breaks the
|
|
170
170
|
compilation of callers that exhaust it. `statusOf(code)` answers the status
|
|
171
171
|
below, as `JanusErrorStatus` — a union of the eight literals, which a
|
|
@@ -190,6 +190,7 @@ if (error instanceof JanusError) {
|
|
|
190
190
|
| `CODE_INVALID` | 401 — a one-time code that does not match: a second factor's, or one sent by e-mail; `attemptsLeft` from either `confirm` belongs in the body |
|
|
191
191
|
| `SECOND_FACTOR_NOT_ENROLLED`, `SECOND_FACTOR_ACTIVE` | 409 — the factor is not in the state the call needs |
|
|
192
192
|
| `USER_INACTIVE` | 403 |
|
|
193
|
+
| `STEP_UP_REQUIRED` | 403 — the session proved who it is too long ago for this action: ask for a step-up, then send the request again |
|
|
193
194
|
| `TOKEN_UNKNOWN`, `TOKEN_SPENT`, `TOKEN_EXPIRED`, `TOKEN_STALE` | 400 |
|
|
194
195
|
| `INVALID_CURSOR` | 400 |
|
|
195
196
|
| `UNSUPPORTED` | 501 — a wiring mistake, and the message names the store to change |
|
|
@@ -197,7 +198,7 @@ if (error instanceof JanusError) {
|
|
|
197
198
|
|
|
198
199
|
Each code has its class, all exported: `StoreFailure`, `StoreConflict` (`on:
|
|
199
200
|
'login' | 'version'`), `NotFoundError`, `UserInvalidError`, `CredentialError`,
|
|
200
|
-
`UserInactiveError`, `TokenError` (the `TOKEN_*` codes and `CODE_INVALID`),
|
|
201
|
+
`UserInactiveError`, `StepUpRequiredError`, `TokenError` (the `TOKEN_*` codes and `CODE_INVALID`),
|
|
201
202
|
`SecondFactorError`, `InvalidCursorError`, `UnsupportedError` and
|
|
202
203
|
`PermissionDepthError`. `StoreFailure` and `StoreConflict` are exported
|
|
203
204
|
**because an adapter throws them**. An adapter defines no error class of its own, so `instanceof` holds
|
|
@@ -323,6 +324,8 @@ await auth.resetPassword.request(email); // … | null
|
|
|
323
324
|
await auth.resetPassword.confirm(token, newPassword);
|
|
324
325
|
await auth.signInCode.request(email); // { code, challenge, email, expiresAt, user } | null
|
|
325
326
|
await auth.signInCode.confirm(challenge, code); // { status: 'signedIn', user, session, token }
|
|
327
|
+
await auth.stepUp.request(user); // { via: 'email', code, challenge, email, expiresAt, user }
|
|
328
|
+
await auth.stepUp.confirm(request, challenge, code); // the request's session, authenticatedAt: now
|
|
326
329
|
|
|
327
330
|
// Several user types
|
|
328
331
|
const clinic = janus({
|
|
@@ -465,12 +468,38 @@ await tokens.spendUserTokens(userId, 'signInCode', now); // 1: `kept`, now
|
|
|
465
468
|
await tokens.spendUserTokens(userId, 'signInCode', now); // 0: none left unspent
|
|
466
469
|
```
|
|
467
470
|
|
|
471
|
+
`reauthenticateSession(id, at)` moves a standing session's `authenticatedAt`
|
|
472
|
+
— what a step-up writes once a signed-in user proved again who they are —
|
|
473
|
+
and answers `null` for a revoked one, which it never brings back:
|
|
474
|
+
|
|
475
|
+
```ts
|
|
476
|
+
const { sessions } = createMemoryStores();
|
|
477
|
+
const session = {
|
|
478
|
+
id: mintId(),
|
|
479
|
+
tokenHash: 'f'.repeat(64),
|
|
480
|
+
userId: mintId(),
|
|
481
|
+
authenticatedAt: new Date('2026-01-01T00:00:00.000Z'),
|
|
482
|
+
expiresAt: new Date(Date.now() + 86_400_000),
|
|
483
|
+
revokedAt: null,
|
|
484
|
+
createdAt: new Date('2026-01-01T00:00:00.000Z'),
|
|
485
|
+
};
|
|
486
|
+
await sessions.insertSession(session);
|
|
487
|
+
await sessions.reauthenticateSession(session.id, new Date()); // { …, authenticatedAt: now }
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
A token of kind `stepUp` is that confirmation's challenge: kept apart from
|
|
491
|
+
`signInCode`, so neither is ever redeemed as the other.
|
|
492
|
+
|
|
468
493
|
An adapter written against `@nxgt/janus` 0.3 does not compile against this
|
|
469
494
|
port until it implements `countAttempt`, nor one written against 0.6 until it
|
|
470
|
-
implements `spendUserTokens`,
|
|
495
|
+
implements `spendUserTokens`, nor one written against 0.11 until it
|
|
496
|
+
implements `reauthenticateSession`, and `janus()` refuses each at wiring —
|
|
471
497
|
[Writing an adapter](docs/guide/adapters.md) has the contracts:
|
|
472
|
-
[`countAttempt`](docs/guide/adapters.md#tokenstorecountattempt)
|
|
473
|
-
[`spendUserTokens`](docs/guide/adapters.md#tokenstorespendusertokens)
|
|
498
|
+
[`countAttempt`](docs/guide/adapters.md#tokenstorecountattempt),
|
|
499
|
+
[`spendUserTokens`](docs/guide/adapters.md#tokenstorespendusertokens) and
|
|
500
|
+
[`reauthenticateSession`](docs/guide/adapters.md#sessionstorereauthenticatesession).
|
|
501
|
+
A store that lists the token kinds — a `CHECK`, a validator's enum — adds
|
|
502
|
+
`stepUp`.
|
|
474
503
|
|
|
475
504
|
### Second factor — `secondFactor`
|
|
476
505
|
|
|
@@ -591,6 +620,46 @@ A six-digit code sent to the user's e-mail signs them in, with no password.
|
|
|
591
620
|
[The sign-in code guide](docs/guide/sign-in-code.md) has the request that
|
|
592
621
|
tells nobody who exists, the challenge in a cookie, every error, and a test.
|
|
593
622
|
|
|
623
|
+
### Step-up — `stepUp` and `assertFresh`
|
|
624
|
+
|
|
625
|
+
```ts
|
|
626
|
+
import { assertFresh } from '@nxgt/janus';
|
|
627
|
+
|
|
628
|
+
// A sensitive route asks for a recent proof: signed in, or confirmed since.
|
|
629
|
+
const current = await auth.authenticate(request);
|
|
630
|
+
if (current === null) return new Response(null, { status: 401 });
|
|
631
|
+
assertFresh(current.session, '10m'); // StepUpRequiredError, STEP_UP_REQUIRED (403), past ten minutes
|
|
632
|
+
|
|
633
|
+
// The client, told STEP_UP_REQUIRED, asks for a step-up:
|
|
634
|
+
const issued = await auth.stepUp.request(current.user);
|
|
635
|
+
if (issued.via === 'email') await sendMail(issued.email, `Confirm it is you: ${issued.code}`);
|
|
636
|
+
// …keeps issued.challenge, and sends it back with the code:
|
|
637
|
+
const session = await auth.stepUp.confirm(request, challenge, code); // authenticatedAt: now
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
A signed-in user proves again who they are before something a stolen
|
|
641
|
+
session should not do alone.
|
|
642
|
+
|
|
643
|
+
- **On every user type with an e-mail**, as `signInCode`. A type with no
|
|
644
|
+
e-mail has no `stepUp`.
|
|
645
|
+
- **`request(user)` answers `via: 'email'`** — a six-digit `code` to send to
|
|
646
|
+
`email` — or, for a user whose second factor is active, **`via:
|
|
647
|
+
'secondFactor'`**: nothing to send, ask for their app's code. A step-up is
|
|
648
|
+
never weaker than the sign-in the account asks for. One step-up is live
|
|
649
|
+
per user; a challenge lives `'10m'` (`tokens.stepUp`).
|
|
650
|
+
- **`confirm(request, challenge, code)` stamps the session the request
|
|
651
|
+
presents**: its `authenticatedAt` moves to now, and it is answered. It
|
|
652
|
+
opens no session and hands out no token. Five attempts per challenge; an
|
|
653
|
+
app's codes are also counted per user, five per 15-minute window, with
|
|
654
|
+
`regenerateRecoveryCodes`. A request whose session is not a standing one
|
|
655
|
+
of the challenge's user is `TOKEN_UNKNOWN`.
|
|
656
|
+
- **`assertFresh(session, maxAge, clock?)`** reads `authenticatedAt` and
|
|
657
|
+
nothing else: `STEP_UP_REQUIRED` (403) when it is `maxAge` old or more. A
|
|
658
|
+
fresh sign-in is fresh too.
|
|
659
|
+
|
|
660
|
+
[The step-up guide](docs/guide/step-up.md) has the two requests, every
|
|
661
|
+
error, and the codes an app confirms.
|
|
662
|
+
|
|
594
663
|
### User events — `events`
|
|
595
664
|
|
|
596
665
|
```ts
|
|
@@ -784,7 +853,7 @@ describeJanusStores({
|
|
|
784
853
|
});
|
|
785
854
|
```
|
|
786
855
|
|
|
787
|
-
There are
|
|
856
|
+
There are 54 cases. They cover:
|
|
788
857
|
- round-trip, byte for byte — including every edge character the core lets
|
|
789
858
|
through (control characters, U+FFFF, a surrogate pair);
|
|
790
859
|
- uniqueness, as a constraint: of twenty concurrent inserts of one login,
|
|
@@ -793,10 +862,15 @@ There are 49 cases. They cover:
|
|
|
793
862
|
- versions: a refused update writes nothing;
|
|
794
863
|
- **omission**, named after the Kratos `PUT` trap;
|
|
795
864
|
- pagination;
|
|
796
|
-
- sessions
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
865
|
+
- sessions: `reauthenticateSession` moves `authenticatedAt` and nothing else,
|
|
866
|
+
and never brings back a revoked session, even one revoked at the same
|
|
867
|
+
moment;
|
|
868
|
+
- one-time tokens: a token of every kind the port names is stored, counted
|
|
869
|
+
and spent — a `CHECK` or an enum that forgot `stepUp` fails here — and a
|
|
870
|
+
step-up is never counted, spent nor answered as a sign-in code; of twenty
|
|
871
|
+
concurrent redemptions, exactly one succeeds; of twenty concurrent
|
|
872
|
+
`countAttempt` calls, each answers a distinct count, and none is counted
|
|
873
|
+
once a racing redemption spent the token;
|
|
800
874
|
- spending a user's tokens of one kind — `spendUserTokens` — spends only the
|
|
801
875
|
unspent ones of that user and kind, spares the one named by `except`, and
|
|
802
876
|
never spends the same token as a racing redemption;
|
|
@@ -805,7 +879,7 @@ There are 49 cases. They cover:
|
|
|
805
879
|
removed by one that names `null`;
|
|
806
880
|
- deletion: a user's logins are freed, and every session and token of theirs
|
|
807
881
|
goes, with a replay answering `false` or `0` rather than failing;
|
|
808
|
-
- **outages**, one case for each of the
|
|
882
|
+
- **outages**, one case for each of the fourteen methods whose honest answer can
|
|
809
883
|
be "nothing".
|
|
810
884
|
|
|
811
885
|
The suite imports no test framework and no assertion library. It runs under
|
|
@@ -852,6 +926,18 @@ the body of the code form — never in the e-mail, never in a URL, where logs,
|
|
|
852
926
|
proxies and the `Referer` header see it, and never in a log. The e-mail holds
|
|
853
927
|
the code and nothing else.
|
|
854
928
|
|
|
929
|
+
**Confirm a step-up on the request that asked for it.** `stepUp.confirm`
|
|
930
|
+
stamps the session the request presents, and only a standing session of
|
|
931
|
+
the challenge's user: a challenge carried to another browser, or confirmed
|
|
932
|
+
after a sign-out, is `TOKEN_UNKNOWN`. Its challenge is a secret like
|
|
933
|
+
`signInCode`'s — and check freshness on the server with `assertFresh`, never
|
|
934
|
+
from a flag the client keeps.
|
|
935
|
+
|
|
936
|
+
**Rate-limit `stepUp.request` per user.** An app's codes are counted per
|
|
937
|
+
user and window, but an e-mailed code gets five guesses per challenge and a
|
|
938
|
+
new challenge takes only a new `request`: without a limit, a stolen session
|
|
939
|
+
can keep asking — and fill the user's inbox while it does.
|
|
940
|
+
|
|
855
941
|
**Answer `signInCode.request` the same whether it issued a code or not** —
|
|
856
942
|
the same status, body and cookie: set a random challenge when it answered
|
|
857
943
|
`null`. The code route then still tells a decoy (`TOKEN_UNKNOWN`) from a
|
|
@@ -1016,17 +1102,17 @@ that sends one, since it is awaited: queue the event and return.
|
|
|
1016
1102
|
|
|
1017
1103
|
## Type safety, counted
|
|
1018
1104
|
|
|
1019
|
-
**One hundred and twenty-
|
|
1105
|
+
**One hundred and twenty-nine plausible mistakes, one hundred and twenty-nine refused at compile time — and
|
|
1020
1106
|
two gaps, named.**
|
|
1021
1107
|
|
|
1022
1108
|
The lists are typechecked and never run, with one `@ts-expect-error` per
|
|
1023
1109
|
mistake beside the shapes that must keep compiling. One is a single file:
|
|
1024
1110
|
`test/types/refusals.ts` (fifteen, on the shared vocabulary). The other three
|
|
1025
|
-
are folders with one file per behaviour: `test/types/port/` (twenty-
|
|
1111
|
+
are folders with one file per behaviour: `test/types/port/` (twenty-four, on
|
|
1026
1112
|
the identity stores' port, from the point of view of the person implementing
|
|
1027
|
-
it), `test/types/auth/` (
|
|
1113
|
+
it), `test/types/auth/` (forty-two, on `janus()`, from the point of view of
|
|
1028
1114
|
the application — twelve of them on the second factor, three on sign-in codes,
|
|
1029
|
-
three on user events) and `test/types/permissions/` (forty-eight, on the
|
|
1115
|
+
three on user events, four on step-ups) and `test/types/permissions/` (forty-eight, on the
|
|
1030
1116
|
permission model and the questions asked of it). The rule comes from
|
|
1031
1117
|
`nxgt-data`, and so does the reason to distrust the claim without the files:
|
|
1032
1118
|
when it was last measured on `@nxgt/mongo`, *seven of twelve plausible
|
|
@@ -48,6 +48,8 @@ interface SharedConfig {
|
|
|
48
48
|
readonly resetPassword?: Duration;
|
|
49
49
|
/** How long an e-mailed sign-in code waits. `'10m'` when absent. */
|
|
50
50
|
readonly signInCode?: Duration;
|
|
51
|
+
/** How long a step-up's challenge waits, e-mailed or not. `'10m'` when absent. */
|
|
52
|
+
readonly stepUp?: Duration;
|
|
51
53
|
};
|
|
52
54
|
/**
|
|
53
55
|
* A TOTP second factor, for every user type with a password. Absent, no
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"janus-config.d.ts","sourceRoot":"","sources":["../../../src/auth/config/janus-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE9D,2DAA2D;AAC3D,MAAM,WAAW,YAAY;IAC5B,oFAAoF;IACpF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,yBAAyB;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,2BAA2B;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC9C,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,UAAU,YAAY;IACrB,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC;IACnC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IAC/C,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE;QACjB,2BAA2B;QAC3B,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC;QAChC,0BAA0B;QAC1B,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC;QAClC,oEAAoE;QACpE,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"janus-config.d.ts","sourceRoot":"","sources":["../../../src/auth/config/janus-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE9D,2DAA2D;AAC3D,MAAM,WAAW,YAAY;IAC5B,oFAAoF;IACpF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,yBAAyB;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,2BAA2B;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC9C,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,UAAU,YAAY;IACrB,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC;IACnC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IAC/C,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE;QACjB,2BAA2B;QAC3B,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC;QAChC,0BAA0B;QAC1B,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC;QAClC,oEAAoE;QACpE,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC;QAC/B,kFAAkF;QAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC;KAC3B,CAAC;IACF;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAC3C;;;;;;;OAOG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC;CACpC;AAED,mFAAmF;AACnF,MAAM,WAAW,kBAAkB;IAClC,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,UAAU,EAAE,GAAG,UAAU,EAAE,CAAC,CAAC;IACtD,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC;CAC9B;AAED,+DAA+D;AAC/D,MAAM,WAAW,gBAChB,SAAQ,YAAY,EACnB,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;CACvB;AAED,mEAAmE;AACnE,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACpD,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,CAAA;KAAE,CAAC;IAC5D,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC;IACzB,QAAQ,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC;CAC/B;AAED,MAAM,MAAM,WAAW,GAAG,gBAAgB,GAAG,eAAe,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolved-config.d.ts","sourceRoot":"","sources":["../../../src/auth/config/resolved-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,oFAAoF;AACpF,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE;QAClB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;QAC9C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;KAC3B,GAAG,IAAI,CAAC;IACT,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAClD,QAAQ,CAAC,UAAU,EAAE;QACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;QAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"resolved-config.d.ts","sourceRoot":"","sources":["../../../src/auth/config/resolved-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,oFAAoF;AACpF,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE;QAClB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;QAC9C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;KAC3B,GAAG,IAAI,CAAC;IACT,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAClD,QAAQ,CAAC,UAAU,EAAE;QACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;QAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,QAAQ,CAAC,YAAY,EAAE;QACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;KAChC,GAAG,IAAI,CAAC;IACT,QAAQ,CAAC,MAAM,EAAE;QAChB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;QAC7C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;KACzB,CAAC;CACF"}
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { assertStores } from './port/assert-stores';
|
|
|
6
6
|
export { createMemoryStores } from './port/memory';
|
|
7
7
|
export type { JanusStores, Json, JsonObject, PasswordRecord, SecondFactorRecord, SessionId, SessionRecord, SessionStore, StoreCapabilities, TokenKind, TokenRecord, TokenStore, UserPageRequest, UserPatch, UserRecord, UserStore, } from './port/types';
|
|
8
8
|
export type { SealingKey } from './sealing';
|
|
9
|
+
export { assertFresh } from './sessions/fresh';
|
|
9
10
|
export type { StandardSchemaV1 } from './standard-schema';
|
|
10
|
-
export type { Authenticated, Checked, EmailOf, HeaderRecord, IssuedCode, IssuedToken, Janus, LoginOf, PasswordApi, RecoveredSignIn, RecoveryCodesIssued, RequestLike, RequiredStringKeys, ResetPasswordApi, SecondFactorApi, SecondFactorEnrolment, SecondFactorRequired, Session, SharedApi, SignedIn, SignInCodeApi, SignInResult, TypeApi, TypesOf, User, UserBase, UserOf, UserRef, UserTypeApi, VerifyEmailApi, WriteOptions, } from './types';
|
|
11
|
+
export type { Authenticated, Checked, EmailOf, HeaderRecord, IssuedCode, IssuedToken, Janus, LoginOf, PasswordApi, RecoveredSignIn, RecoveryCodesIssued, RequestLike, RequiredStringKeys, ResetPasswordApi, SecondFactorApi, SecondFactorEnrolment, SecondFactorRequired, Session, SharedApi, SignedIn, SignInCodeApi, SignInResult, StepUpApi, StepUpByApp, StepUpByEmail, TypeApi, TypesOf, User, UserBase, UserOf, UserRef, UserTypeApi, VerifyEmailApi, WriteOptions, } from './types';
|
|
11
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/auth/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,YAAY,EACZ,UAAU,EACV,WAAW,EACX,eAAe,EACf,SAAS,EACT,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,cAAc,GACd,MAAM,UAAU,CAAC;AAClB,YAAY,EACX,SAAS,EACT,iBAAiB,EACjB,aAAa,GACb,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,YAAY,EACX,WAAW,EACX,IAAI,EACJ,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,SAAS,EACT,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,UAAU,EACV,eAAe,EACf,SAAS,EACT,UAAU,EACV,SAAS,GACT,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,YAAY,EACX,aAAa,EACb,OAAO,EACP,OAAO,EACP,YAAY,EACZ,UAAU,EACV,WAAW,EACX,KAAK,EACL,OAAO,EACP,WAAW,EACX,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,OAAO,EACP,SAAS,EACT,QAAQ,EACR,aAAa,EACb,YAAY,EACZ,OAAO,EACP,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,MAAM,EACN,OAAO,EACP,WAAW,EACX,cAAc,EACd,YAAY,GACZ,MAAM,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,YAAY,EACZ,UAAU,EACV,WAAW,EACX,eAAe,EACf,SAAS,EACT,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,cAAc,GACd,MAAM,UAAU,CAAC;AAClB,YAAY,EACX,SAAS,EACT,iBAAiB,EACjB,aAAa,GACb,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,YAAY,EACX,WAAW,EACX,IAAI,EACJ,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,SAAS,EACT,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,UAAU,EACV,eAAe,EACf,SAAS,EACT,UAAU,EACV,SAAS,GACT,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,YAAY,EACX,aAAa,EACb,OAAO,EACP,OAAO,EACP,YAAY,EACZ,UAAU,EACV,WAAW,EACX,KAAK,EACL,OAAO,EACP,WAAW,EACX,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,OAAO,EACP,SAAS,EACT,QAAQ,EACR,aAAa,EACb,YAAY,EACZ,SAAS,EACT,WAAW,EACX,aAAa,EACb,OAAO,EACP,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,MAAM,EACN,OAAO,EACP,WAAW,EACX,cAAc,EACd,YAAY,GACZ,MAAM,SAAS,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assert-stores.d.ts","sourceRoot":"","sources":["../../../src/auth/port/assert-stores.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,iBAAiB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"assert-stores.d.ts","sourceRoot":"","sources":["../../../src/auth/port/assert-stores.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAoC9D;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC3B,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,MAAM,GACX,iBAAiB,CAmCnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../../../src/auth/port/memory/sessions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA4B,YAAY,EAAE,MAAM,UAAU,CAAC;AASvE,mCAAmC;AACnC,wBAAgB,kBAAkB,IAAI,YAAY,
|
|
1
|
+
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../../../src/auth/port/memory/sessions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA4B,YAAY,EAAE,MAAM,UAAU,CAAC;AASvE,mCAAmC;AACnC,wBAAgB,kBAAkB,IAAI,YAAY,CAkEjD"}
|
|
@@ -20,7 +20,10 @@ export interface SessionRecord {
|
|
|
20
20
|
/** `sha256` of the session token, hex. Unique across the store. */
|
|
21
21
|
readonly tokenHash: string;
|
|
22
22
|
readonly userId: Id;
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* When credentials were last presented — at the sign-in, or since by a
|
|
25
|
+
* step-up on this session — not when the session was last extended.
|
|
26
|
+
*/
|
|
24
27
|
readonly authenticatedAt: Date;
|
|
25
28
|
readonly expiresAt: Date;
|
|
26
29
|
/** `null` while the session stands. */
|
|
@@ -53,6 +56,18 @@ export interface SessionStore {
|
|
|
53
56
|
* *allowed* to be extended yet is the core's decision, made before the call.
|
|
54
57
|
*/
|
|
55
58
|
extendSession(id: SessionId, expiresAt: Date): Promise<SessionRecord | null>;
|
|
59
|
+
/**
|
|
60
|
+
* Moves `authenticatedAt` to `at`, **only while the session is not
|
|
61
|
+
* revoked**, and answers the record as written: what a step-up calls once
|
|
62
|
+
* the user proved again, on this session, who they are. `expiresAt` and
|
|
63
|
+
* every other field stay as they were.
|
|
64
|
+
*
|
|
65
|
+
* `null` when there is no such session or it has been revoked — a
|
|
66
|
+
* confirmation racing a revocation must never bring the session back.
|
|
67
|
+
* Whether the session may be confirmed — standing, not lapsed — is the
|
|
68
|
+
* core's decision, made before the call.
|
|
69
|
+
*/
|
|
70
|
+
reauthenticateSession(id: SessionId, at: Date): Promise<SessionRecord | null>;
|
|
56
71
|
/**
|
|
57
72
|
* Revokes one session. `true` when the session exists — revoked by this call
|
|
58
73
|
* or already — and `false` when there is none.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../../../src/auth/port/types/sessions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAE1C,mEAAmE;AACnE,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAE/B;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC;IACvB,mEAAmE;IACnE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;IACpB
|
|
1
|
+
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../../../src/auth/port/types/sessions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAE1C,mEAAmE;AACnE,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAE/B;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC;IACvB,mEAAmE;IACnE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,eAAe,EAAE,IAAI,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,uCAAuC;IACvC,QAAQ,CAAC,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC5B;;;OAGG;IACH,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpD,mEAAmE;IACnE,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAEzE;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAE7E;;;;;;;;;;OAUG;IACH,qBAAqB,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAE9E;;;;;OAKG;IACH,aAAa,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEzD;;;;OAIG;IACH,kBAAkB,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE9E;;;;;OAKG;IACH,kBAAkB,CAAC,MAAM,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEhD;;;;;;;;OAQG;IACH,qBAAqB,CAAC,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACtD"}
|
|
@@ -16,8 +16,12 @@ import type { Id } from '../../../ids/id';
|
|
|
16
16
|
* attempts at `regenerateRecoveryCodes`, a token of this kind whose secret
|
|
17
17
|
* nobody is given, never redeemed, only counted.
|
|
18
18
|
* - `signInCode`: a code sent by e-mail to sign in without a password.
|
|
19
|
+
* - `stepUp`: a signed-in user's confirmation of a sensitive action — a code
|
|
20
|
+
* sent by e-mail, or, with an active second factor, a code from their app.
|
|
21
|
+
* A kind of its own, so a sign-in code never confirms an action nor an
|
|
22
|
+
* action's code signs anyone in.
|
|
19
23
|
*/
|
|
20
|
-
export type TokenKind = 'verifyEmail' | 'resetPassword' | 'secondFactor' | 'signInCode';
|
|
24
|
+
export type TokenKind = 'verifyEmail' | 'resetPassword' | 'secondFactor' | 'signInCode' | 'stepUp';
|
|
21
25
|
/** A one-time token, as a store holds it: its hash, never its secret. */
|
|
22
26
|
export interface TokenRecord {
|
|
23
27
|
/** `sha256` of the token's secret, hex. Unique across the store. */
|
|
@@ -30,7 +34,8 @@ export interface TokenRecord {
|
|
|
30
34
|
*/
|
|
31
35
|
readonly address: string;
|
|
32
36
|
/**
|
|
33
|
-
* For a token redeemed with
|
|
37
|
+
* For a token redeemed with an e-mailed code — `signInCode`, and a
|
|
38
|
+
* `stepUp` sent by e-mail — the code's hash, keyed
|
|
34
39
|
* by the token's secret, so the tokens alone do not reveal it. `null` for
|
|
35
40
|
* every other kind: the core writes it so, and a store keeps what it is
|
|
36
41
|
* given.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../../src/auth/port/types/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAE1C
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../../src/auth/port/types/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAE1C;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,SAAS,GAClB,aAAa,GACb,eAAe,GACf,cAAc,GACd,YAAY,GACZ,QAAQ,CAAC;AAEZ,yEAAyE;AACzE,MAAM,WAAW,WAAW;IAC3B,oEAAoE;IACpE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,mDAAmD;IACnD,QAAQ,CAAC,OAAO,EAAE,IAAI,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;CACzB;AAED,kDAAkD;AAClD,MAAM,WAAW,UAAU;IAC1B;;;OAGG;IACH,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhD;;;;;;;;;;;;;;;;;;OAkBG;IACH,YAAY,CACX,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,SAAS,EACf,EAAE,EAAE,IAAI,GACN,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAE/B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAE9E;;;;;;;;;;;;;;;;OAgBG;IACH,eAAe,CACd,MAAM,EAAE,EAAE,EACV,IAAI,EAAE,SAAS,EACf,EAAE,EAAE,IAAI,EACR,MAAM,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnB;;;;OAIG;IACH,gBAAgB,CAAC,MAAM,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9C"}
|
|
@@ -2,9 +2,11 @@ import type { Context } from '../context';
|
|
|
2
2
|
import type { UserRecord } from '../port/types';
|
|
3
3
|
import type { Sealer } from '../sealing';
|
|
4
4
|
/**
|
|
5
|
-
* The attempts at
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* The attempts at an app's code outside a sign-in — `regenerateRecoveryCodes`
|
|
6
|
+
* and a step-up confirmed with the app — counted by the store, in one count
|
|
7
|
+
* both share: the same {@link CODE_ATTEMPTS} a challenge takes, per user and
|
|
8
|
+
* per window, so a stolen session cannot guess the app's code at leisure,
|
|
9
|
+
* nor buy more guesses by switching from one to the other.
|
|
8
10
|
*
|
|
9
11
|
* **No port of its own.** The count is a one-time token of kind
|
|
10
12
|
* `secondFactor`, counted by `countAttempt` like a challenge's: one
|
|
@@ -13,7 +15,7 @@ import type { Sealer } from '../sealing';
|
|
|
13
15
|
* without the sealing keys can name it — nor redeem it as a challenge.
|
|
14
16
|
*
|
|
15
17
|
* What it is for decides when it starts again: the **window**, a fixed
|
|
16
|
-
* {@link
|
|
18
|
+
* {@link APP_CODE_WINDOW_MS} slice of the clock, and the factor's
|
|
17
19
|
* `lastStep`, which **any code accepted** moves — a regenerate that
|
|
18
20
|
* succeeded starts the count again, and so does a sign-in finished with the
|
|
19
21
|
* app.
|
|
@@ -24,11 +26,12 @@ import type { Sealer } from '../sealing';
|
|
|
24
26
|
* from them — a password written between guesses buys none.
|
|
25
27
|
*/
|
|
26
28
|
/** How long the attempts of one window last: fifteen minutes. */
|
|
27
|
-
export declare const
|
|
29
|
+
export declare const APP_CODE_WINDOW_MS: number;
|
|
28
30
|
/**
|
|
29
|
-
* Counts one attempt at
|
|
30
|
-
*
|
|
31
|
-
*
|
|
31
|
+
* Counts one attempt at the app's code — to regenerate the user's recovery
|
|
32
|
+
* codes, or to confirm a step-up — before the code is compared, and
|
|
33
|
+
* answers how many are left. Past the last one, it refuses — the right
|
|
34
|
+
* code included — until the window ends.
|
|
32
35
|
*/
|
|
33
|
-
export declare function
|
|
34
|
-
//# sourceMappingURL=
|
|
36
|
+
export declare function countAppCodeAttempt(context: Context, sealer: Sealer, record: UserRecord, where: string): Promise<number>;
|
|
37
|
+
//# sourceMappingURL=app-code-attempts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-code-attempts.d.ts","sourceRoot":"","sources":["../../../src/auth/second-factor/app-code-attempts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,KAAK,EAAe,UAAU,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAGzC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,iEAAiE;AACjE,eAAO,MAAM,kBAAkB,QAAc,CAAC;AA8C9C;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACxC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CAgBjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authenticate.d.ts","sourceRoot":"","sources":["../../../src/auth/sessions/authenticate.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"authenticate.d.ts","sourceRoot":"","sources":["../../../src/auth/sessions/authenticate.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,YAAY,CAAC;AAEhE,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAI3D,oFAAoF;AACpF,wBAAsB,YAAY,CACjC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAClC,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CA0CxC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `assertFresh`: whether a session proved who it is recently enough for a
|
|
3
|
+
* sensitive action — signed in, or confirmed by a step-up, less than
|
|
4
|
+
* `maxAge` ago.
|
|
5
|
+
*/
|
|
6
|
+
import { type Clock } from '../../time/clock';
|
|
7
|
+
import { type Duration } from '../../time/duration';
|
|
8
|
+
import type { Session } from '../types';
|
|
9
|
+
/**
|
|
10
|
+
* Refuses a session whose credentials were last presented `maxAge` ago or
|
|
11
|
+
* more — at its sign-in, or since by `stepUp.confirm` — with
|
|
12
|
+
* `STEP_UP_REQUIRED` (403): ask for a step-up, then run the action again. One
|
|
13
|
+
* field of the session `authenticate` already answered, so no store is read.
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* const current = await auth.authenticate(request);
|
|
17
|
+
* if (current === null) return new Response(null, { status: 401 });
|
|
18
|
+
* assertFresh(current.session, '10m'); // STEP_UP_REQUIRED past ten minutes
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* Pass the `clock` given to `janus()` when it is not the system's. A
|
|
22
|
+
* `maxAge` that is not a duration is a `TypeError`: it is written in the
|
|
23
|
+
* code, never read from a request.
|
|
24
|
+
*/
|
|
25
|
+
export declare function assertFresh(session: Pick<Session, 'authenticatedAt' | 'userId'>, maxAge: Duration, clock?: Clock): void;
|
|
26
|
+
//# sourceMappingURL=fresh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fresh.d.ts","sourceRoot":"","sources":["../../../src/auth/sessions/fresh.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,KAAK,KAAK,EAAe,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,KAAK,QAAQ,EAAiB,MAAM,qBAAqB,CAAC;AACnE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAC1B,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,iBAAiB,GAAG,QAAQ,CAAC,EACpD,MAAM,EAAE,QAAQ,EAChB,KAAK,GAAE,KAAmB,GACxB,IAAI,CASN"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The standing session a request presents — one rule for `authenticate` and
|
|
3
|
+
* `stepUp.confirm`, so the two never disagree on what "signed in" means.
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '../context';
|
|
6
|
+
import type { SessionRecord } from '../port/types';
|
|
7
|
+
import type { RequestLike } from '../types';
|
|
8
|
+
/** A standing session, and the session token that presented it. */
|
|
9
|
+
export interface Presented {
|
|
10
|
+
readonly token: string;
|
|
11
|
+
readonly session: SessionRecord;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Answers the session `request` presents, with its token — or `null` when
|
|
15
|
+
* none stands: no token, or a session gone, revoked or lapsed. Expiry is
|
|
16
|
+
* decided here, against the context's clock: a store may still hold a
|
|
17
|
+
* session past its term.
|
|
18
|
+
*/
|
|
19
|
+
export declare function standingSession(context: Context, request: RequestLike): Promise<Presented | null>;
|
|
20
|
+
//# sourceMappingURL=standing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"standing.d.ts","sourceRoot":"","sources":["../../../src/auth/sessions/standing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAG5C,mEAAmE;AACnE,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACpC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,WAAW,GAClB,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAa3B"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two codes that confirm a step-up: the one e-mailed with the challenge,
|
|
3
|
+
* and, for a user whose second factor is active, the one their app shows.
|
|
4
|
+
* Each spends the challenge once it matched.
|
|
5
|
+
*/
|
|
6
|
+
import type { ResolvedType } from '../config';
|
|
7
|
+
import type { Context } from '../context';
|
|
8
|
+
import type { TokenRecord, UserRecord } from '../port/types';
|
|
9
|
+
/** A challenge counted: the token as counted, its secret, and what is left of its attempts. */
|
|
10
|
+
export interface CountedStepUp {
|
|
11
|
+
readonly token: TokenRecord;
|
|
12
|
+
readonly secret: string;
|
|
13
|
+
readonly attemptsLeft: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Checks the e-mailed code. Refused when the user's second factor became
|
|
17
|
+
* active since it was sent — their app is what confirms now — and when the
|
|
18
|
+
* e-mail it was sent to is not theirs any more.
|
|
19
|
+
*/
|
|
20
|
+
export declare function checkEmailedCode(context: Context, type: ResolvedType, user: UserRecord, counted: CountedStepUp, code: string, where: string): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Checks a code from the user's app. Its attempts are counted twice before it
|
|
23
|
+
* is compared: against the challenge, and per user and window, as
|
|
24
|
+
* `regenerateRecoveryCodes`' are — a stolen session asking for challenge
|
|
25
|
+
* after challenge still gets five guesses per window, not five per
|
|
26
|
+
* challenge. The code accepted is written, so it confirms nothing else.
|
|
27
|
+
*/
|
|
28
|
+
export declare function checkAppCode(context: Context, type: ResolvedType, user: UserRecord, counted: CountedStepUp, code: string, where: string): Promise<void>;
|
|
29
|
+
//# sourceMappingURL=codes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codes.d.ts","sourceRoot":"","sources":["../../../src/auth/step-up/codes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAQ1C,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI7D,+FAA+F;AAC/F,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC9B;AAKD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACrC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CACjC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CA0Cf"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A step-up: a signed-in user proving again who they are before a sensitive
|
|
3
|
+
* action, with a code sent by e-mail — or from their app, when their second
|
|
4
|
+
* factor is active — and **the session they are on stamped as freshly
|
|
5
|
+
* confirmed**. It opens no session: its `authenticatedAt` moves, which is
|
|
6
|
+
* what a route checks with `assertFresh`.
|
|
7
|
+
*
|
|
8
|
+
* The same six digits, challenge and five attempts as a sign-in code, on a
|
|
9
|
+
* token kind of its own: a sign-in code never confirms an action, nor an
|
|
10
|
+
* action's code signs anyone in.
|
|
11
|
+
*/
|
|
12
|
+
import type { At } from '../at';
|
|
13
|
+
import type { ResolvedType } from '../config';
|
|
14
|
+
import type { AnyUser, Context } from '../context';
|
|
15
|
+
import type { StepUpApi } from '../types';
|
|
16
|
+
import { type IssuedStepUp } from './request';
|
|
17
|
+
/** The step-up of one user type. */
|
|
18
|
+
export declare function stepUpFlows(context: Context, type: ResolvedType, at: At): StepUpApi<AnyUser, IssuedStepUp>['stepUp'];
|
|
19
|
+
//# sourceMappingURL=flows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flows.d.ts","sourceRoot":"","sources":["../../../src/auth/step-up/flows.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAGnD,OAAO,KAAK,EAAwB,SAAS,EAAE,MAAM,UAAU,CAAC;AAGhE,OAAO,EAAE,KAAK,YAAY,EAAiB,MAAM,WAAW,CAAC;AAE7D,oCAAoC;AACpC,wBAAgB,WAAW,CAC1B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,EAAE,EAAE,EAAE,GACJ,SAAS,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,QAAQ,CAAC,CAiB5C"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What confirming a step-up takes before any code is compared: the session
|
|
3
|
+
* the request presents, and the user the challenge is for — the two the
|
|
4
|
+
* same, both standing.
|
|
5
|
+
*/
|
|
6
|
+
import type { ResolvedType } from '../config';
|
|
7
|
+
import { type Context } from '../context';
|
|
8
|
+
import type { SessionRecord, TokenRecord, UserRecord } from '../port/types';
|
|
9
|
+
import type { RequestLike } from '../types';
|
|
10
|
+
/** The session a step-up confirms, and its user. */
|
|
11
|
+
export interface OpenedStepUp {
|
|
12
|
+
readonly session: SessionRecord;
|
|
13
|
+
readonly user: UserRecord;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Reads the session the request presents and the user the challenge is for.
|
|
17
|
+
* A session absent, revoked, lapsed, or another user's is as good as no
|
|
18
|
+
* challenge — a challenge is confirmed on its user's own session, never on
|
|
19
|
+
* somebody else's — and so is a user gone since, or of another type. Each
|
|
20
|
+
* attempt was counted before, so the last one spends the challenge.
|
|
21
|
+
*/
|
|
22
|
+
export declare function openStepUp(context: Context, type: ResolvedType, request: RequestLike, token: TokenRecord, secret: string, where: string): Promise<OpenedStepUp>;
|
|
23
|
+
//# sourceMappingURL=open.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open.d.ts","sourceRoot":"","sources":["../../../src/auth/step-up/open.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,KAAK,OAAO,EAAc,MAAM,YAAY,CAAC;AAEtD,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,oDAAoD;AACpD,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC/B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,CAkBvB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Issuing a step-up: a challenge for the user, with a code to e-mail, or to
|
|
3
|
+
* confirm with their app when their second factor is active.
|
|
4
|
+
*/
|
|
5
|
+
import type { ResolvedType } from '../config';
|
|
6
|
+
import { type AnyUser, type Context } from '../context';
|
|
7
|
+
import type { StepUpByApp, StepUpByEmail, UserRef } from '../types';
|
|
8
|
+
/** What `stepUp.request` answers, whatever the type's configuration. */
|
|
9
|
+
export type IssuedStepUp = StepUpByEmail<AnyUser> | StepUpByApp<AnyUser>;
|
|
10
|
+
/** Issues a step-up for the user, and spends every other they had. */
|
|
11
|
+
export declare function requestStepUp(context: Context, type: ResolvedType, user: UserRef, where: string): Promise<IssuedStepUp>;
|
|
12
|
+
//# sourceMappingURL=request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../../src/auth/step-up/request.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,OAAO,EAKZ,MAAM,YAAY,CAAC;AAKpB,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEpE,wEAAwE;AACxE,MAAM,MAAM,YAAY,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;AAEzE,sEAAsE;AACtE,wBAAsB,aAAa,CAClC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,CAqBvB"}
|
|
@@ -15,6 +15,7 @@ export type { PasswordApi } from './password';
|
|
|
15
15
|
export type { RecoveredSignIn, RecoveryCodesIssued, SecondFactorApi, SecondFactorEnrolment, } from './second-factor';
|
|
16
16
|
export type { Authenticated, HeaderRecord, RequestLike, Session, } from './session';
|
|
17
17
|
export type { SecondFactorRequired, SignedIn, SignInResult, } from './sign-in';
|
|
18
|
+
export type { StepUpApi, StepUpByApp, StepUpByEmail } from './step-up';
|
|
18
19
|
export type { User, UserBase, UserRef, WriteOptions } from './user';
|
|
19
20
|
export type { UserTypeApi } from './user-type';
|
|
20
21
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EACX,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,cAAc,GACd,MAAM,eAAe,CAAC;AACvB,YAAY,EACX,OAAO,EACP,OAAO,EACP,kBAAkB,EAClB,OAAO,EACP,MAAM,GACN,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,YAAY,EACX,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,qBAAqB,GACrB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACX,aAAa,EACb,YAAY,EACZ,WAAW,EACX,OAAO,GACP,MAAM,WAAW,CAAC;AACnB,YAAY,EACX,oBAAoB,EACpB,QAAQ,EACR,YAAY,GACZ,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACpE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EACX,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,cAAc,GACd,MAAM,eAAe,CAAC;AACvB,YAAY,EACX,OAAO,EACP,OAAO,EACP,kBAAkB,EAClB,OAAO,EACP,MAAM,GACN,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,YAAY,EACX,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,qBAAqB,GACrB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACX,aAAa,EACb,YAAY,EACZ,WAAW,EACX,OAAO,GACP,MAAM,WAAW,CAAC;AACnB,YAAY,EACX,oBAAoB,EACpB,QAAQ,EACR,YAAY,GACZ,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACvE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACpE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -11,13 +11,14 @@ import type { PasswordApi } from './password';
|
|
|
11
11
|
import type { SecondFactorApi } from './second-factor';
|
|
12
12
|
import type { Authenticated, RequestLike, Session } from './session';
|
|
13
13
|
import type { SignedIn, SignInResult } from './sign-in';
|
|
14
|
+
import type { StepUpApi, StepUpByApp, StepUpByEmail } from './step-up';
|
|
14
15
|
import type { UserRef } from './user';
|
|
15
16
|
import type { UserTypeApi } from './user-type';
|
|
16
17
|
/**
|
|
17
18
|
* The whole surface of one user type, with only the flows its configuration
|
|
18
19
|
* allows. `TwoFactor` is whether `janus()` was given a `secondFactor`.
|
|
19
20
|
*/
|
|
20
|
-
export type TypeApi<Name extends string, Def, TwoFactor extends boolean = false> = UserTypeApi<UserOfType<Name, Def>, FieldsInput<Def>> & ([LoginOf<Def>] extends [never] ? unknown : TwoFactor extends true ? PasswordApi<UserOfType<Name, Def>, FieldsInput<Def>, LoginOf<Def>, SignInResult<UserOfType<Name, Def>>> & SecondFactorApi<UserOfType<Name, Def>> : PasswordApi<UserOfType<Name, Def>, FieldsInput<Def>, LoginOf<Def>>) & ([EmailOf<Def>] extends [never] ? unknown : VerifyEmailApi<UserOfType<Name, Def>> & SignInCodeApi<UserOfType<Name, Def>, TwoFactor extends true ? [LoginOf<Def>] extends [never] ? SignedIn<UserOfType<Name, Def>> : SignInResult<UserOfType<Name, Def>> : SignedIn<UserOfType<Name, Def>>>) & ([LoginOf<Def>] extends [never] ? unknown : [EmailOf<Def>] extends [never] ? unknown : ResetPasswordApi<UserOfType<Name, Def>>);
|
|
21
|
+
export type TypeApi<Name extends string, Def, TwoFactor extends boolean = false> = UserTypeApi<UserOfType<Name, Def>, FieldsInput<Def>> & ([LoginOf<Def>] extends [never] ? unknown : TwoFactor extends true ? PasswordApi<UserOfType<Name, Def>, FieldsInput<Def>, LoginOf<Def>, SignInResult<UserOfType<Name, Def>>> & SecondFactorApi<UserOfType<Name, Def>> : PasswordApi<UserOfType<Name, Def>, FieldsInput<Def>, LoginOf<Def>>) & ([EmailOf<Def>] extends [never] ? unknown : VerifyEmailApi<UserOfType<Name, Def>> & SignInCodeApi<UserOfType<Name, Def>, TwoFactor extends true ? [LoginOf<Def>] extends [never] ? SignedIn<UserOfType<Name, Def>> : SignInResult<UserOfType<Name, Def>> : SignedIn<UserOfType<Name, Def>>> & StepUpApi<UserOfType<Name, Def>, TwoFactor extends true ? [LoginOf<Def>] extends [never] ? StepUpByEmail<UserOfType<Name, Def>> : StepUpByEmail<UserOfType<Name, Def>> | StepUpByApp<UserOfType<Name, Def>> : StepUpByEmail<UserOfType<Name, Def>>>) & ([LoginOf<Def>] extends [never] ? unknown : [EmailOf<Def>] extends [never] ? unknown : ResetPasswordApi<UserOfType<Name, Def>>);
|
|
21
22
|
/** What every configuration answers, whatever its user types. */
|
|
22
23
|
export interface SharedApi<U extends {
|
|
23
24
|
readonly type: string;
|