@c9up/visa 0.1.0 → 0.1.2
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/dist/VisaManager.d.ts +40 -7
- package/dist/VisaManager.d.ts.map +1 -1
- package/dist/VisaManager.js +79 -3
- package/dist/VisaManager.js.map +1 -1
- package/dist/VisaProvider.d.ts.map +1 -1
- package/dist/VisaProvider.js +56 -0
- package/dist/VisaProvider.js.map +1 -1
- package/dist/authorize.d.ts +18 -0
- package/dist/authorize.d.ts.map +1 -1
- package/dist/authorize.js +6 -0
- package/dist/authorize.js.map +1 -1
- package/dist/config.d.ts +35 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/configure.d.ts.map +1 -1
- package/dist/configure.js +19 -0
- package/dist/configure.js.map +1 -1
- package/dist/errors.d.ts +9 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/guard.d.ts +243 -0
- package/dist/guard.d.ts.map +1 -0
- package/dist/guard.js +293 -0
- package/dist/guard.js.map +1 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/introspect.d.ts +11 -1
- package/dist/introspect.d.ts.map +1 -1
- package/dist/introspect.js +27 -1
- package/dist/introspect.js.map +1 -1
- package/dist/protectedResource.d.ts +81 -0
- package/dist/protectedResource.d.ts.map +1 -0
- package/dist/protectedResource.js +124 -0
- package/dist/protectedResource.js.map +1 -0
- package/dist/register.d.ts +96 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +173 -0
- package/dist/register.js.map +1 -0
- package/dist/resource.d.ts +50 -0
- package/dist/resource.d.ts.map +1 -0
- package/dist/resource.js +101 -0
- package/dist/resource.js.map +1 -0
- package/dist/store.d.ts +33 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/stores/atlas.d.ts +106 -0
- package/dist/stores/atlas.d.ts.map +1 -0
- package/dist/stores/atlas.js +408 -0
- package/dist/stores/atlas.js.map +1 -0
- package/dist/stores/memory.d.ts +5 -0
- package/dist/stores/memory.d.ts.map +1 -1
- package/dist/stores/memory.js +30 -0
- package/dist/stores/memory.js.map +1 -1
- package/dist/token.d.ts +2 -0
- package/dist/token.d.ts.map +1 -1
- package/dist/token.js +21 -1
- package/dist/token.js.map +1 -1
- package/dist/types.d.ts +49 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -1
- package/src/VisaManager.ts +109 -3
- package/src/VisaProvider.ts +64 -0
- package/src/authorize.ts +27 -0
- package/src/config.ts +35 -0
- package/src/configure.ts +21 -0
- package/src/errors.ts +16 -2
- package/src/guard.ts +443 -0
- package/src/index.ts +41 -0
- package/src/introspect.ts +33 -2
- package/src/protectedResource.ts +171 -0
- package/src/register.ts +296 -0
- package/src/resource.ts +123 -0
- package/src/store.ts +38 -0
- package/src/stores/atlas.ts +514 -0
- package/src/stores/memory.ts +38 -0
- package/src/token.ts +45 -1
- package/src/types.ts +50 -0
- package/stubs/database/migrations/9000_create_visa_tables.stub +112 -0
package/dist/guard.d.ts
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `visaGuard()` — authenticating a request with an OAuth access token.
|
|
3
|
+
*
|
|
4
|
+
* Declared in `config/auth.ts` beside `jwtGuard` and `sessionGuard`, and it
|
|
5
|
+
* behaves like the access-tokens guard upstream: the authenticated user carries
|
|
6
|
+
* a `currentAccessToken` whose `abilities` are the token's scopes, with
|
|
7
|
+
* `allows`, `denies`, `authorize`, `isExpired()` and `lastUsedAt` answering
|
|
8
|
+
* exactly as they do there. `allows` treats `*` as every ability, which is the
|
|
9
|
+
* upstream rule read off `@adonisjs/auth`'s build rather than recalled.
|
|
10
|
+
*
|
|
11
|
+
* Two things this fixes for every application at once. A route gate no longer
|
|
12
|
+
* has to introspect the token itself — the scopes are on the guard's token. And
|
|
13
|
+
* the user is fetched through the application's own provider on every request,
|
|
14
|
+
* so an account disabled after the token was issued is refused here instead of
|
|
15
|
+
* in each application that remembers to check.
|
|
16
|
+
*
|
|
17
|
+
* NO import of warden. A guard is structurally `{ name, authenticate, verify }`
|
|
18
|
+
* and that is all warden asks for, so visa stays a package you can run without
|
|
19
|
+
* it — the same rule every other package in this universe follows.
|
|
20
|
+
*/
|
|
21
|
+
import type { VisaStore } from "./store.js";
|
|
22
|
+
/**
|
|
23
|
+
* The user shape a guard hands back.
|
|
24
|
+
*
|
|
25
|
+
* `id` and the two optional arrays are what warden reads; everything else the
|
|
26
|
+
* application's provider returns travels with it untouched.
|
|
27
|
+
*/
|
|
28
|
+
export interface GuardUser {
|
|
29
|
+
id: string;
|
|
30
|
+
roles?: string[];
|
|
31
|
+
permissions?: string[];
|
|
32
|
+
/** The token this request was authenticated with. Set by the guard. */
|
|
33
|
+
currentAccessToken?: VisaAccessToken;
|
|
34
|
+
[key: string]: unknown;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* What the guard needs from the store, and nothing more.
|
|
38
|
+
*
|
|
39
|
+
* A narrow slice rather than the whole contract: authenticating reads one row
|
|
40
|
+
* and records one use, so that is what it asks for. A full {@link VisaStore}
|
|
41
|
+
* satisfies it, and a resource server that keeps only tokens can implement two
|
|
42
|
+
* methods instead of twelve.
|
|
43
|
+
*/
|
|
44
|
+
export type GuardStore = Pick<VisaStore, "findAccessToken" | "touchAccessToken" | "saveAccessToken" | "revokeAccessToken">;
|
|
45
|
+
/** What a guard answers. Warden's `AuthResult`, declared here so visa owes it nothing. */
|
|
46
|
+
export interface GuardResult {
|
|
47
|
+
authenticated: boolean;
|
|
48
|
+
user?: GuardUser;
|
|
49
|
+
error?: string;
|
|
50
|
+
}
|
|
51
|
+
/** What a test client sends to be this user. Warden's `AuthClientResponse`. */
|
|
52
|
+
export interface GuardClientResponse {
|
|
53
|
+
headers?: Record<string, string>;
|
|
54
|
+
session?: Record<string, unknown>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The token behind the current request.
|
|
58
|
+
*
|
|
59
|
+
* Upstream's `AccessToken`, minus what an opaque OAuth token has no equivalent
|
|
60
|
+
* for: there is no `identifier`/`secret` pair to decode here, because visa
|
|
61
|
+
* stores a hash and the plaintext never comes back.
|
|
62
|
+
*/
|
|
63
|
+
export declare class VisaAccessToken {
|
|
64
|
+
/** The client the token was issued to — an OAuth token always has one. */
|
|
65
|
+
readonly clientId: string;
|
|
66
|
+
/** Absent for `client_credentials`: there is no user behind it. */
|
|
67
|
+
readonly userId?: string;
|
|
68
|
+
/** The token's scopes. Named `abilities` for the upstream surface. */
|
|
69
|
+
readonly abilities: string[];
|
|
70
|
+
/**
|
|
71
|
+
* A recognisable name, as upstream carries one.
|
|
72
|
+
*
|
|
73
|
+
* An OAuth token is not named by the user who holds it — it is named by the
|
|
74
|
+
* client it was issued to — so this is the client's name when the store
|
|
75
|
+
* knows it, and null otherwise.
|
|
76
|
+
*/
|
|
77
|
+
readonly name: string | null;
|
|
78
|
+
readonly expiresAt: Date | null;
|
|
79
|
+
readonly lastUsedAt: Date | null;
|
|
80
|
+
/**
|
|
81
|
+
* The token itself, and only just after it was created.
|
|
82
|
+
*
|
|
83
|
+
* Upstream's `value`: the one moment the plaintext exists is when it is
|
|
84
|
+
* minted, because what is stored is a hash. A token read back from the
|
|
85
|
+
* store never has it, and that is not a gap — it is why a database copy is
|
|
86
|
+
* not a set of working tokens.
|
|
87
|
+
*/
|
|
88
|
+
readonly value?: string;
|
|
89
|
+
constructor(attributes: {
|
|
90
|
+
clientId: string;
|
|
91
|
+
userId?: string;
|
|
92
|
+
abilities: string[];
|
|
93
|
+
name?: string | null;
|
|
94
|
+
expiresAt?: Date | null;
|
|
95
|
+
lastUsedAt?: Date | null;
|
|
96
|
+
value?: string;
|
|
97
|
+
});
|
|
98
|
+
/** `*` means every ability — upstream's rule, read off its build. */
|
|
99
|
+
allows(ability: string): boolean;
|
|
100
|
+
denies(ability: string): boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Throw unless the token carries `ability`.
|
|
103
|
+
*
|
|
104
|
+
* The upstream error id verbatim, so a handler that already maps
|
|
105
|
+
* `E_UNAUTHORIZED_ACCESS` keeps working.
|
|
106
|
+
*/
|
|
107
|
+
authorize(ability: string): void;
|
|
108
|
+
/** A token with no expiry never expires. */
|
|
109
|
+
isExpired(): boolean;
|
|
110
|
+
/** Upstream's keys, plus the client an OAuth token always belongs to. */
|
|
111
|
+
toJSON(): {
|
|
112
|
+
type: "bearer";
|
|
113
|
+
name: string | null;
|
|
114
|
+
token: string | undefined;
|
|
115
|
+
clientId: string;
|
|
116
|
+
abilities: string[];
|
|
117
|
+
lastUsedAt: Date | null;
|
|
118
|
+
expiresAt: Date | null;
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
export interface VisaGuardConfig {
|
|
122
|
+
/**
|
|
123
|
+
* Where the tokens live. A function, so the guard can be built in
|
|
124
|
+
* `config/auth.ts` before the provider has seated the manager — config is
|
|
125
|
+
* read at boot, and the store exists a moment later.
|
|
126
|
+
*/
|
|
127
|
+
store: GuardStore | (() => GuardStore);
|
|
128
|
+
/**
|
|
129
|
+
* The application's user provider — upstream's `tokensUserProvider({ model })`.
|
|
130
|
+
*
|
|
131
|
+
* Called on every authenticated request, deliberately: a token issued to an
|
|
132
|
+
* account that has since been disabled must stop working, and the only way
|
|
133
|
+
* to know is to ask. Answer `null` and the request is refused.
|
|
134
|
+
*/
|
|
135
|
+
findUser: (userId: string) => Promise<GuardUser | null>;
|
|
136
|
+
/**
|
|
137
|
+
* What a `client_credentials` token authenticates as, when anything.
|
|
138
|
+
*
|
|
139
|
+
* There is no user behind that grant, so by default such a token does not
|
|
140
|
+
* authenticate a user at all and the guard refuses. An application that
|
|
141
|
+
* serves machine callers supplies this and gets a subject of its choosing.
|
|
142
|
+
*/
|
|
143
|
+
findClientSubject?: (clientId: string) => Promise<GuardUser | null>;
|
|
144
|
+
/** Guard name, for `auth.use(name)`. Defaults to `visa`. */
|
|
145
|
+
name?: string;
|
|
146
|
+
/**
|
|
147
|
+
* The client a token minted by {@link VisaGuard.createToken} belongs to.
|
|
148
|
+
*
|
|
149
|
+
* Upstream's guard needs no such thing because it has no clients. Here
|
|
150
|
+
* every token is issued TO somebody, and one with no client could not be
|
|
151
|
+
* introspected, revoked by its owner, or listed on a "connected
|
|
152
|
+
* applications" screen. Name the first-party application and a minted
|
|
153
|
+
* token is an ordinary token in every other respect.
|
|
154
|
+
*/
|
|
155
|
+
tokenClientId?: string;
|
|
156
|
+
/** How long a minted token lasts — upstream's `expiresIn`, in seconds. */
|
|
157
|
+
expiresInSeconds?: number;
|
|
158
|
+
/**
|
|
159
|
+
* The protected resource this guard stands in front of (RFC 9728).
|
|
160
|
+
*
|
|
161
|
+
* Given, {@link VisaGuard.challenge} returns a `WWW-Authenticate` naming
|
|
162
|
+
* the metadata document, which is how an MCP client finds the
|
|
163
|
+
* authorization server without being told where it is.
|
|
164
|
+
*/
|
|
165
|
+
resource?: string;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* A guard, in the shape warden's config expects.
|
|
169
|
+
*
|
|
170
|
+
* Shared per application, so it holds no per-request state — the same rule
|
|
171
|
+
* warden states for its own strategies.
|
|
172
|
+
*/
|
|
173
|
+
export declare class VisaGuard {
|
|
174
|
+
#private;
|
|
175
|
+
readonly name: string;
|
|
176
|
+
constructor(config: VisaGuardConfig);
|
|
177
|
+
/**
|
|
178
|
+
* There is no password flow here, and OAuth 2.1 removed the one there used
|
|
179
|
+
* to be. A token comes from the token endpoint.
|
|
180
|
+
*
|
|
181
|
+
* THROWS rather than answering "not authenticated", which is what warden's
|
|
182
|
+
* own access-tokens guard does: a bearer guard handed an email and a
|
|
183
|
+
* password is a misconfigured application, not a bad credential, and the two
|
|
184
|
+
* must not produce the same 401.
|
|
185
|
+
*/
|
|
186
|
+
authenticate(): Promise<GuardResult>;
|
|
187
|
+
/**
|
|
188
|
+
* Mint a token for `user`, as upstream's guard does.
|
|
189
|
+
*
|
|
190
|
+
* The token is a real one: stored hashed, listed, introspectable,
|
|
191
|
+
* revocable. What it skips is the authorization code flow, so it is for a
|
|
192
|
+
* FIRST-PARTY client you own — `tokenClientId` — and nothing here should
|
|
193
|
+
* ever be handed a third-party client id.
|
|
194
|
+
*/
|
|
195
|
+
createToken(user: {
|
|
196
|
+
id: string;
|
|
197
|
+
} | string, abilities?: string[], options?: {
|
|
198
|
+
name?: string;
|
|
199
|
+
expiresInSeconds?: number;
|
|
200
|
+
}): Promise<VisaAccessToken>;
|
|
201
|
+
/**
|
|
202
|
+
* Revoke a token — upstream's `invalidateToken`.
|
|
203
|
+
*
|
|
204
|
+
* NAMED DEVIATION — upstream's guard is built per request and invalidates
|
|
205
|
+
* the token it just authenticated with, so it takes no argument. A warden
|
|
206
|
+
* strategy is shared by the whole application and holds no per-request
|
|
207
|
+
* state, by warden's own rule, so the token to revoke is passed in. A
|
|
208
|
+
* sign-out handler has it: it is the bearer credential of the request.
|
|
209
|
+
*
|
|
210
|
+
* Answers whether the token was there to revoke.
|
|
211
|
+
*/
|
|
212
|
+
invalidateToken(presented: string): Promise<boolean>;
|
|
213
|
+
/**
|
|
214
|
+
* What a test client sends to be `user` — upstream's signature.
|
|
215
|
+
*
|
|
216
|
+
* It mints a token, as upstream does, so a test authenticates the way the
|
|
217
|
+
* application will rather than against a credential the store has never
|
|
218
|
+
* seen.
|
|
219
|
+
*/
|
|
220
|
+
authenticateAsClient(user: {
|
|
221
|
+
id: string;
|
|
222
|
+
} | string, abilities?: string[], options?: {
|
|
223
|
+
name?: string;
|
|
224
|
+
expiresInSeconds?: number;
|
|
225
|
+
}): Promise<GuardClientResponse>;
|
|
226
|
+
/**
|
|
227
|
+
* The `WWW-Authenticate` value a 401 from this guard should carry.
|
|
228
|
+
*
|
|
229
|
+
* Returned rather than set: a warden strategy answers whether a credential
|
|
230
|
+
* is good, and the response belongs to whoever refuses the request. An
|
|
231
|
+
* exception handler sets it — `response.header('www-authenticate',
|
|
232
|
+
* guard.challenge())` — and with it a client that has no token learns
|
|
233
|
+
* where to get one instead of hitting a dead end.
|
|
234
|
+
*/
|
|
235
|
+
challenge(options?: {
|
|
236
|
+
error?: string;
|
|
237
|
+
scope?: readonly string[];
|
|
238
|
+
}): string;
|
|
239
|
+
verify(presented: string): Promise<GuardResult>;
|
|
240
|
+
}
|
|
241
|
+
/** Build a visa guard from its config — `visaGuard({...})` in `config/auth.ts`. */
|
|
242
|
+
export declare function visaGuard(config: VisaGuardConfig): VisaGuard;
|
|
243
|
+
//# sourceMappingURL=guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"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"}
|
package/dist/guard.js
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `visaGuard()` — authenticating a request with an OAuth access token.
|
|
3
|
+
*
|
|
4
|
+
* Declared in `config/auth.ts` beside `jwtGuard` and `sessionGuard`, and it
|
|
5
|
+
* behaves like the access-tokens guard upstream: the authenticated user carries
|
|
6
|
+
* a `currentAccessToken` whose `abilities` are the token's scopes, with
|
|
7
|
+
* `allows`, `denies`, `authorize`, `isExpired()` and `lastUsedAt` answering
|
|
8
|
+
* exactly as they do there. `allows` treats `*` as every ability, which is the
|
|
9
|
+
* upstream rule read off `@adonisjs/auth`'s build rather than recalled.
|
|
10
|
+
*
|
|
11
|
+
* Two things this fixes for every application at once. A route gate no longer
|
|
12
|
+
* has to introspect the token itself — the scopes are on the guard's token. And
|
|
13
|
+
* the user is fetched through the application's own provider on every request,
|
|
14
|
+
* so an account disabled after the token was issued is refused here instead of
|
|
15
|
+
* in each application that remembers to check.
|
|
16
|
+
*
|
|
17
|
+
* NO import of warden. A guard is structurally `{ name, authenticate, verify }`
|
|
18
|
+
* and that is all warden asks for, so visa stays a package you can run without
|
|
19
|
+
* it — the same rule every other package in this universe follows.
|
|
20
|
+
*/
|
|
21
|
+
import { hashSecret, randomToken } from "./crypto.js";
|
|
22
|
+
import { verifyAccessToken } from "./introspect.js";
|
|
23
|
+
import { wwwAuthenticate } from "./protectedResource.js";
|
|
24
|
+
/**
|
|
25
|
+
* The token behind the current request.
|
|
26
|
+
*
|
|
27
|
+
* Upstream's `AccessToken`, minus what an opaque OAuth token has no equivalent
|
|
28
|
+
* for: there is no `identifier`/`secret` pair to decode here, because visa
|
|
29
|
+
* stores a hash and the plaintext never comes back.
|
|
30
|
+
*/
|
|
31
|
+
export class VisaAccessToken {
|
|
32
|
+
/** The client the token was issued to — an OAuth token always has one. */
|
|
33
|
+
clientId;
|
|
34
|
+
/** Absent for `client_credentials`: there is no user behind it. */
|
|
35
|
+
userId;
|
|
36
|
+
/** The token's scopes. Named `abilities` for the upstream surface. */
|
|
37
|
+
abilities;
|
|
38
|
+
/**
|
|
39
|
+
* A recognisable name, as upstream carries one.
|
|
40
|
+
*
|
|
41
|
+
* An OAuth token is not named by the user who holds it — it is named by the
|
|
42
|
+
* client it was issued to — so this is the client's name when the store
|
|
43
|
+
* knows it, and null otherwise.
|
|
44
|
+
*/
|
|
45
|
+
name;
|
|
46
|
+
expiresAt;
|
|
47
|
+
lastUsedAt;
|
|
48
|
+
/**
|
|
49
|
+
* The token itself, and only just after it was created.
|
|
50
|
+
*
|
|
51
|
+
* Upstream's `value`: the one moment the plaintext exists is when it is
|
|
52
|
+
* minted, because what is stored is a hash. A token read back from the
|
|
53
|
+
* store never has it, and that is not a gap — it is why a database copy is
|
|
54
|
+
* not a set of working tokens.
|
|
55
|
+
*/
|
|
56
|
+
value;
|
|
57
|
+
constructor(attributes) {
|
|
58
|
+
this.clientId = attributes.clientId;
|
|
59
|
+
if (attributes.userId !== undefined)
|
|
60
|
+
this.userId = attributes.userId;
|
|
61
|
+
this.abilities = [...attributes.abilities];
|
|
62
|
+
this.name = attributes.name ?? null;
|
|
63
|
+
this.expiresAt = attributes.expiresAt ?? null;
|
|
64
|
+
this.lastUsedAt = attributes.lastUsedAt ?? null;
|
|
65
|
+
if (attributes.value !== undefined)
|
|
66
|
+
this.value = attributes.value;
|
|
67
|
+
}
|
|
68
|
+
/** `*` means every ability — upstream's rule, read off its build. */
|
|
69
|
+
allows(ability) {
|
|
70
|
+
return this.abilities.includes(ability) || this.abilities.includes("*");
|
|
71
|
+
}
|
|
72
|
+
denies(ability) {
|
|
73
|
+
return !this.allows(ability);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Throw unless the token carries `ability`.
|
|
77
|
+
*
|
|
78
|
+
* The upstream error id verbatim, so a handler that already maps
|
|
79
|
+
* `E_UNAUTHORIZED_ACCESS` keeps working.
|
|
80
|
+
*/
|
|
81
|
+
authorize(ability) {
|
|
82
|
+
if (this.allows(ability))
|
|
83
|
+
return;
|
|
84
|
+
const error = new Error(`Access denied: the token does not carry "${ability}"`);
|
|
85
|
+
error.code = "E_UNAUTHORIZED_ACCESS";
|
|
86
|
+
error.status = 403;
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
/** A token with no expiry never expires. */
|
|
90
|
+
isExpired() {
|
|
91
|
+
if (this.expiresAt === null)
|
|
92
|
+
return false;
|
|
93
|
+
return this.expiresAt.getTime() <= Date.now();
|
|
94
|
+
}
|
|
95
|
+
/** Upstream's keys, plus the client an OAuth token always belongs to. */
|
|
96
|
+
toJSON() {
|
|
97
|
+
return {
|
|
98
|
+
type: "bearer",
|
|
99
|
+
name: this.name,
|
|
100
|
+
// Present exactly once, on the token `createToken` just returned —
|
|
101
|
+
// which is the only time a caller can hand it to anybody.
|
|
102
|
+
token: this.value,
|
|
103
|
+
clientId: this.clientId,
|
|
104
|
+
abilities: this.abilities,
|
|
105
|
+
lastUsedAt: this.lastUsedAt,
|
|
106
|
+
expiresAt: this.expiresAt,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/** An hour, as the token endpoint uses by default. */
|
|
111
|
+
const DEFAULT_TTL = 3600;
|
|
112
|
+
/**
|
|
113
|
+
* A guard, in the shape warden's config expects.
|
|
114
|
+
*
|
|
115
|
+
* Shared per application, so it holds no per-request state — the same rule
|
|
116
|
+
* warden states for its own strategies.
|
|
117
|
+
*/
|
|
118
|
+
export class VisaGuard {
|
|
119
|
+
name;
|
|
120
|
+
#config;
|
|
121
|
+
constructor(config) {
|
|
122
|
+
this.#config = config;
|
|
123
|
+
this.name = config.name ?? "visa";
|
|
124
|
+
}
|
|
125
|
+
#store() {
|
|
126
|
+
const store = this.#config.store;
|
|
127
|
+
return typeof store === "function" ? store() : store;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* There is no password flow here, and OAuth 2.1 removed the one there used
|
|
131
|
+
* to be. A token comes from the token endpoint.
|
|
132
|
+
*
|
|
133
|
+
* THROWS rather than answering "not authenticated", which is what warden's
|
|
134
|
+
* own access-tokens guard does: a bearer guard handed an email and a
|
|
135
|
+
* password is a misconfigured application, not a bad credential, and the two
|
|
136
|
+
* must not produce the same 401.
|
|
137
|
+
*/
|
|
138
|
+
async authenticate() {
|
|
139
|
+
throw new Error("visa authenticates a bearer token, not credentials. Use verify() with the access token.");
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Mint a token for `user`, as upstream's guard does.
|
|
143
|
+
*
|
|
144
|
+
* The token is a real one: stored hashed, listed, introspectable,
|
|
145
|
+
* revocable. What it skips is the authorization code flow, so it is for a
|
|
146
|
+
* FIRST-PARTY client you own — `tokenClientId` — and nothing here should
|
|
147
|
+
* ever be handed a third-party client id.
|
|
148
|
+
*/
|
|
149
|
+
async createToken(user, abilities = ["*"], options = {}) {
|
|
150
|
+
const clientId = this.#config.tokenClientId;
|
|
151
|
+
if (clientId === undefined) {
|
|
152
|
+
throw new Error("[visa] createToken needs `tokenClientId` — a token is always issued to a client. Name the first-party application in visaGuard({ tokenClientId }).");
|
|
153
|
+
}
|
|
154
|
+
const userId = typeof user === "string" ? user : user.id;
|
|
155
|
+
const ttl = options.expiresInSeconds ?? this.#config.expiresInSeconds ?? DEFAULT_TTL;
|
|
156
|
+
const secret = randomToken();
|
|
157
|
+
const expiresAt = new Date(Date.now() + ttl * 1000);
|
|
158
|
+
await this.#store().saveAccessToken({
|
|
159
|
+
tokenHash: hashSecret(secret),
|
|
160
|
+
clientId,
|
|
161
|
+
userId,
|
|
162
|
+
scopes: abilities,
|
|
163
|
+
expiresAt,
|
|
164
|
+
});
|
|
165
|
+
return new VisaAccessToken({
|
|
166
|
+
clientId,
|
|
167
|
+
userId,
|
|
168
|
+
abilities,
|
|
169
|
+
name: options.name ?? null,
|
|
170
|
+
expiresAt,
|
|
171
|
+
// The one moment the plaintext exists.
|
|
172
|
+
value: secret,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Revoke a token — upstream's `invalidateToken`.
|
|
177
|
+
*
|
|
178
|
+
* NAMED DEVIATION — upstream's guard is built per request and invalidates
|
|
179
|
+
* the token it just authenticated with, so it takes no argument. A warden
|
|
180
|
+
* strategy is shared by the whole application and holds no per-request
|
|
181
|
+
* state, by warden's own rule, so the token to revoke is passed in. A
|
|
182
|
+
* sign-out handler has it: it is the bearer credential of the request.
|
|
183
|
+
*
|
|
184
|
+
* Answers whether the token was there to revoke.
|
|
185
|
+
*/
|
|
186
|
+
async invalidateToken(presented) {
|
|
187
|
+
const store = this.#store();
|
|
188
|
+
const hash = hashSecret(presented);
|
|
189
|
+
const existing = await store.findAccessToken(hash);
|
|
190
|
+
if (existing === null || existing.revokedAt !== undefined)
|
|
191
|
+
return false;
|
|
192
|
+
await store.revokeAccessToken(hash, new Date());
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* What a test client sends to be `user` — upstream's signature.
|
|
197
|
+
*
|
|
198
|
+
* It mints a token, as upstream does, so a test authenticates the way the
|
|
199
|
+
* application will rather than against a credential the store has never
|
|
200
|
+
* seen.
|
|
201
|
+
*/
|
|
202
|
+
async authenticateAsClient(user, abilities = ["*"], options = {}) {
|
|
203
|
+
const token = await this.createToken(user, abilities, options);
|
|
204
|
+
return { headers: { authorization: `Bearer ${token.value}` } };
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* The `WWW-Authenticate` value a 401 from this guard should carry.
|
|
208
|
+
*
|
|
209
|
+
* Returned rather than set: a warden strategy answers whether a credential
|
|
210
|
+
* is good, and the response belongs to whoever refuses the request. An
|
|
211
|
+
* exception handler sets it — `response.header('www-authenticate',
|
|
212
|
+
* guard.challenge())` — and with it a client that has no token learns
|
|
213
|
+
* where to get one instead of hitting a dead end.
|
|
214
|
+
*/
|
|
215
|
+
challenge(options = {}) {
|
|
216
|
+
return wwwAuthenticate({
|
|
217
|
+
...(this.#config.resource === undefined
|
|
218
|
+
? {}
|
|
219
|
+
: { resource: this.#config.resource }),
|
|
220
|
+
...(options.error === undefined ? {} : { error: options.error }),
|
|
221
|
+
...(options.scope === undefined ? {} : { scope: options.scope }),
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
async verify(presented) {
|
|
225
|
+
const store = this.#store();
|
|
226
|
+
const now = new Date();
|
|
227
|
+
const verified = await verifyAccessToken(presented, store, now);
|
|
228
|
+
if (verified === null) {
|
|
229
|
+
return { authenticated: false, error: "Invalid or expired access token" };
|
|
230
|
+
}
|
|
231
|
+
const subject = verified.userId === undefined
|
|
232
|
+
? await this.#config.findClientSubject?.(verified.clientId)
|
|
233
|
+
: await this.#config.findUser(verified.userId);
|
|
234
|
+
if (subject === null || subject === undefined) {
|
|
235
|
+
// The account is gone or disabled since the token was minted. Refusing
|
|
236
|
+
// here is the point of asking on every request.
|
|
237
|
+
return {
|
|
238
|
+
authenticated: false,
|
|
239
|
+
error: verified.userId === undefined
|
|
240
|
+
? "This token authenticates no user"
|
|
241
|
+
: "The account behind this token is no longer available",
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
// The PREVIOUS use is what the token reports, and this one is recorded
|
|
245
|
+
// after — the same order upstream reads its row in.
|
|
246
|
+
await touch(store, presented, now);
|
|
247
|
+
const token = new VisaAccessToken({
|
|
248
|
+
clientId: verified.clientId,
|
|
249
|
+
...(verified.userId === undefined ? {} : { userId: verified.userId }),
|
|
250
|
+
abilities: verified.scopes,
|
|
251
|
+
expiresAt: verified.expiresAt ?? null,
|
|
252
|
+
lastUsedAt: verified.lastUsedAt ?? null,
|
|
253
|
+
});
|
|
254
|
+
// A copy: the provider's object is the application's, and a guard that
|
|
255
|
+
// mutated it would leak one request's token into the next.
|
|
256
|
+
const user = { ...subject, currentAccessToken: token };
|
|
257
|
+
if (verified.scopes.length > 0) {
|
|
258
|
+
// Scopes surface on `permissions` as well, the way warden's access-token
|
|
259
|
+
// guard does it, so `ctx.auth.user.permissions` reads the same whichever
|
|
260
|
+
// guard authenticated.
|
|
261
|
+
//
|
|
262
|
+
// They remain a SEPARATE axis from the route-level rights gate, exactly
|
|
263
|
+
// as upstream: a token ability is checked with
|
|
264
|
+
// `currentAccessToken.allows(...)`, and Bouncer does not consult it.
|
|
265
|
+
user.permissions = [
|
|
266
|
+
...new Set([...(subject.permissions ?? []), ...verified.scopes]),
|
|
267
|
+
];
|
|
268
|
+
}
|
|
269
|
+
return { authenticated: true, user };
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Record that the token was just used.
|
|
274
|
+
*
|
|
275
|
+
* Never fatal: a store with no `touchAccessToken` — the contract shipped
|
|
276
|
+
* without one — still authenticates, it simply reports no last use.
|
|
277
|
+
*/
|
|
278
|
+
async function touch(store, presented, now) {
|
|
279
|
+
if (store.touchAccessToken === undefined)
|
|
280
|
+
return;
|
|
281
|
+
try {
|
|
282
|
+
await store.touchAccessToken(hashSecret(presented), now);
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
// Recording the use is bookkeeping; failing it must not refuse a request
|
|
286
|
+
// whose token is valid.
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
/** Build a visa guard from its config — `visaGuard({...})` in `config/auth.ts`. */
|
|
290
|
+
export function visaGuard(config) {
|
|
291
|
+
return new VisaGuard(config);
|
|
292
|
+
}
|
|
293
|
+
//# sourceMappingURL=guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.js","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -14,12 +14,17 @@ export { type AuthorizationRequest, type AuthorizeOptions, errorRedirect, issueA
|
|
|
14
14
|
export { assertGrantAllowed, authenticateClient, type ClientCredentials, readCredentials, redirectUriMatches, resolveScopes, } from "./clients.js";
|
|
15
15
|
export { defineConfig, type VisaConfigInput } from "./config.js";
|
|
16
16
|
export { hashSecret, randomToken, secretMatches, sha256 } from "./crypto.js";
|
|
17
|
-
export { type AuthorizationErrorCode, OAuthError, type ProtocolErrorCode, type TokenErrorCode, VisaError, } from "./errors.js";
|
|
17
|
+
export { type AuthorizationErrorCode, OAuthError, type ProtocolErrorCode, type RegistrationErrorCode, type TokenErrorCode, VisaError, } from "./errors.js";
|
|
18
|
+
export { type GuardClientResponse, type GuardResult, type GuardStore, type GuardUser, VisaAccessToken, VisaGuard, type VisaGuardConfig, visaGuard, } from "./guard.js";
|
|
18
19
|
export { introspect, revoke, verifyAccessToken } from "./introspect.js";
|
|
20
|
+
export { assertResourceIdentifier, type ChallengeOptions, PROTECTED_RESOURCE_PATH, type ProtectedResourceMetadata, type ProtectedResourceOptions, protectedResourceMetadata, protectedResourceMetadataUrl, wwwAuthenticate, } from "./protectedResource.js";
|
|
21
|
+
export { type ClientRegistrationRequest, type ClientRegistrationResponse, type RegistrationOptions, registrationResponse, validateRegistration, } from "./register.js";
|
|
22
|
+
export { audienceAllows, narrowResources, readResourceParameter, validateResources, } from "./resource.js";
|
|
19
23
|
export { clearVisa, default as visa, getVisa, setVisa, } from "./services/main.js";
|
|
20
24
|
export type { VisaStore } from "./store.js";
|
|
25
|
+
export { type AtlasDb, type AtlasQuery, AtlasStore, type AtlasStoreTables, } from "./stores/atlas.js";
|
|
21
26
|
export { MemoryStore } from "./stores/memory.js";
|
|
22
27
|
export { type TokenOptions, type TokenRequest, token } from "./token.js";
|
|
23
|
-
export type { AccessToken, AuthorizationCode, Client, ClientAuthMethod, Consent, GrantType, IntrospectionResponse, RefreshToken, TokenResponse, } from "./types.js";
|
|
28
|
+
export type { AccessToken, AuthorizationCode, AuthorizedApplication, Client, ClientAuthMethod, Consent, GrantType, IntrospectionResponse, RefreshToken, TokenResponse, } from "./types.js";
|
|
24
29
|
export { type AuthorizationOutcome, type VisaConfig, VisaManager, } from "./VisaManager.js";
|
|
25
30
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,oBAAoB,CAAC;AAE5B,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,aAAa,EACb,sBAAsB,EACtB,eAAe,EACf,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,4BAA4B,GAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,iBAAiB,EACtB,eAAe,EACf,kBAAkB,EAClB,aAAa,GACb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EACN,KAAK,sBAAsB,EAC3B,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,SAAS,GACT,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EACN,SAAS,EACT,OAAO,IAAI,IAAI,EACf,OAAO,EACP,OAAO,GACP,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACzE,YAAY,EACX,WAAW,EACX,iBAAiB,EACjB,MAAM,EACN,gBAAgB,EAChB,OAAO,EACP,SAAS,EACT,qBAAqB,EACrB,YAAY,EACZ,aAAa,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,UAAU,EACf,WAAW,GACX,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,oBAAoB,CAAC;AAE5B,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,aAAa,EACb,sBAAsB,EACtB,eAAe,EACf,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,4BAA4B,GAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,iBAAiB,EACtB,eAAe,EACf,kBAAkB,EAClB,aAAa,GACb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EACN,KAAK,sBAAsB,EAC3B,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,SAAS,GACT,MAAM,aAAa,CAAC;AACrB,OAAO,EACN,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,SAAS,EACd,eAAe,EACf,SAAS,EACT,KAAK,eAAe,EACpB,SAAS,GACT,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EACN,wBAAwB,EACxB,KAAK,gBAAgB,EACrB,uBAAuB,EACvB,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,yBAAyB,EACzB,4BAA4B,EAC5B,eAAe,GACf,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACN,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACxB,oBAAoB,EACpB,oBAAoB,GACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACN,cAAc,EACd,eAAe,EACf,qBAAqB,EACrB,iBAAiB,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EACN,SAAS,EACT,OAAO,IAAI,IAAI,EACf,OAAO,EACP,OAAO,GACP,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,UAAU,EACf,UAAU,EACV,KAAK,gBAAgB,GACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACzE,YAAY,EACX,WAAW,EACX,iBAAiB,EACjB,qBAAqB,EACrB,MAAM,EACN,gBAAgB,EAChB,OAAO,EACP,SAAS,EACT,qBAAqB,EACrB,YAAY,EACZ,aAAa,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,UAAU,EACf,WAAW,GACX,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -15,8 +15,13 @@ export { assertGrantAllowed, authenticateClient, readCredentials, redirectUriMat
|
|
|
15
15
|
export { defineConfig } from "./config.js";
|
|
16
16
|
export { hashSecret, randomToken, secretMatches, sha256 } from "./crypto.js";
|
|
17
17
|
export { OAuthError, VisaError, } from "./errors.js";
|
|
18
|
+
export { VisaAccessToken, VisaGuard, visaGuard, } from "./guard.js";
|
|
18
19
|
export { introspect, revoke, verifyAccessToken } from "./introspect.js";
|
|
20
|
+
export { assertResourceIdentifier, PROTECTED_RESOURCE_PATH, protectedResourceMetadata, protectedResourceMetadataUrl, wwwAuthenticate, } from "./protectedResource.js";
|
|
21
|
+
export { registrationResponse, validateRegistration, } from "./register.js";
|
|
22
|
+
export { audienceAllows, narrowResources, readResourceParameter, validateResources, } from "./resource.js";
|
|
19
23
|
export { clearVisa, default as visa, getVisa, setVisa, } from "./services/main.js";
|
|
24
|
+
export { AtlasStore, } from "./stores/atlas.js";
|
|
20
25
|
export { MemoryStore } from "./stores/memory.js";
|
|
21
26
|
export { token } from "./token.js";
|
|
22
27
|
export { VisaManager, } from "./VisaManager.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,oBAAoB,CAAC;AAE5B,OAAO,EAGN,aAAa,EACb,sBAAsB,EACtB,eAAe,EACf,mBAAmB,EAEnB,4BAA4B,GAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,kBAAkB,EAClB,kBAAkB,EAElB,eAAe,EACf,kBAAkB,EAClB,aAAa,GACb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAwB,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EAEN,UAAU,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,oBAAoB,CAAC;AAE5B,OAAO,EAGN,aAAa,EACb,sBAAsB,EACtB,eAAe,EACf,mBAAmB,EAEnB,4BAA4B,GAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,kBAAkB,EAClB,kBAAkB,EAElB,eAAe,EACf,kBAAkB,EAClB,aAAa,GACb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAwB,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EAEN,UAAU,EAIV,SAAS,GACT,MAAM,aAAa,CAAC;AACrB,OAAO,EAKN,eAAe,EACf,SAAS,EAET,SAAS,GACT,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EACN,wBAAwB,EAExB,uBAAuB,EAGvB,yBAAyB,EACzB,4BAA4B,EAC5B,eAAe,GACf,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAIN,oBAAoB,EACpB,oBAAoB,GACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACN,cAAc,EACd,eAAe,EACf,qBAAqB,EACrB,iBAAiB,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EACN,SAAS,EACT,OAAO,IAAI,IAAI,EACf,OAAO,EACP,OAAO,GACP,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAGN,UAAU,GAEV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAwC,KAAK,EAAE,MAAM,YAAY,CAAC;AAazE,OAAO,EAGN,WAAW,GACX,MAAM,kBAAkB,CAAC"}
|
package/dist/introspect.d.ts
CHANGED
|
@@ -24,9 +24,19 @@ export declare function revoke(request: Record<string, unknown>, credentials: Cl
|
|
|
24
24
|
* What a resource server calls on every request — so it reads the store
|
|
25
25
|
* directly instead of going through introspection's client authentication.
|
|
26
26
|
*/
|
|
27
|
-
export declare function verifyAccessToken(presented: string, store: VisaStore, now?: Date
|
|
27
|
+
export declare function verifyAccessToken(presented: string, store: Pick<VisaStore, "findAccessToken">, now?: Date,
|
|
28
|
+
/**
|
|
29
|
+
* This resource's identifier (RFC 8707).
|
|
30
|
+
*
|
|
31
|
+
* Given, a token minted for a different resource is refused here rather
|
|
32
|
+
* than honoured — which is the entire point of binding one.
|
|
33
|
+
*/
|
|
34
|
+
resource?: string): Promise<{
|
|
28
35
|
clientId: string;
|
|
29
36
|
userId?: string;
|
|
30
37
|
scopes: string[];
|
|
38
|
+
expiresAt: Date;
|
|
39
|
+
lastUsedAt?: Date;
|
|
40
|
+
audience?: string[];
|
|
31
41
|
} | null>;
|
|
32
42
|
//# sourceMappingURL=introspect.d.ts.map
|
package/dist/introspect.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../src/introspect.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../src/introspect.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAI1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAKxD,wBAAsB,UAAU,CAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,WAAW,EAAE,iBAAiB,EAC9B,KAAK,EAAE,SAAS,EAChB,GAAG,GAAE,IAAiB,EACtB,MAAM,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,qBAAqB,CAAC,CAyDhC;AAED;;;;;;GAMG;AACH,wBAAsB,MAAM,CAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,WAAW,EAAE,iBAAiB,EAC9B,KAAK,EAAE,SAAS,EAChB,GAAG,GAAE,IAAiB,GACpB,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACtC,SAAS,EAAE,MAAM,EAGjB,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EACzC,GAAG,GAAE,IAAiB;AACtB;;;;;GAKG;AACH,QAAQ,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;IACV,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,GAAG,IAAI,CAAC,CAoBR"}
|