@c9up/visa 0.1.3 → 0.1.4
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 +82 -11
- package/dist/VisaManager.d.ts +47 -0
- package/dist/VisaManager.d.ts.map +1 -1
- package/dist/VisaManager.js +169 -7
- package/dist/VisaManager.js.map +1 -1
- package/dist/VisaProvider.d.ts +4 -0
- package/dist/VisaProvider.d.ts.map +1 -1
- package/dist/VisaProvider.js +87 -5
- package/dist/VisaProvider.js.map +1 -1
- package/dist/configure.d.ts.map +1 -1
- package/dist/configure.js +16 -1
- package/dist/configure.js.map +1 -1
- package/dist/guard.d.ts +2 -1
- package/dist/guard.d.ts.map +1 -1
- package/dist/guard.js +12 -13
- package/dist/guard.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/register.d.ts.map +1 -1
- package/dist/register.js +9 -4
- package/dist/register.js.map +1 -1
- package/dist/store.d.ts +10 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/stores/atlas.d.ts +1 -1
- package/dist/stores/atlas.d.ts.map +1 -1
- package/dist/stores/atlas.js +6 -1
- package/dist/stores/atlas.js.map +1 -1
- package/dist/stores/memory.d.ts +1 -2
- package/dist/stores/memory.d.ts.map +1 -1
- package/dist/stores/memory.js +1 -3
- package/dist/stores/memory.js.map +1 -1
- package/dist/token.js +17 -5
- package/dist/token.js.map +1 -1
- package/package.json +1 -1
- package/src/VisaManager.ts +212 -11
- package/src/VisaProvider.ts +108 -6
- package/src/configure.ts +17 -1
- package/src/guard.ts +12 -13
- package/src/index.ts +1 -0
- package/src/register.ts +11 -4
- package/src/store.ts +11 -0
- package/src/stores/atlas.ts +6 -1
- package/src/stores/memory.ts +1 -3
- package/src/token.ts +30 -11
- package/stubs/database/migrations/9000_create_visa_tables.stub +2 -0
- package/stubs/database/migrations/9001_add_visa_client_secret_expiry.stub +29 -0
package/README.md
CHANGED
|
@@ -41,13 +41,39 @@ consent screen, and both belong to your application. See below.
|
|
|
41
41
|
- **Refresh rotation with replay detection.** Every use mints a new token; a
|
|
42
42
|
spent one coming back proves a leak, and since there is no telling the thief
|
|
43
43
|
from the victim, the whole family goes.
|
|
44
|
+
- **Parameters in the body only.** `/token`, `/introspect`, `/revoke` and
|
|
45
|
+
`/register` read the request body only, and answer `invalid_request` to a
|
|
46
|
+
request that puts an OAuth parameter (`client_secret`, `code`, `token`,
|
|
47
|
+
`refresh_token`, registration metadata on `/register`…) in the query
|
|
48
|
+
string: a secret, a code or a token in a URL ends up in access logs,
|
|
49
|
+
proxies and traces (RFC 6749 §2.3.1). Other query parameters are ignored.
|
|
50
|
+
- **A scope is not a permission.** `visaGuard()` puts the token's scopes on
|
|
51
|
+
`ctx.auth.user.currentAccessToken` (`allows`, `denies`, `authorize`) and
|
|
52
|
+
leaves `user.permissions` as your user provider returned it. A scope is
|
|
53
|
+
chosen by the client and granted by consent, which never checks the user's
|
|
54
|
+
own rights — so a route that needs both checks both.
|
|
44
55
|
- **One sentence per failure.** "No such code", "expired", "already used" and
|
|
45
56
|
"wrong client" are `invalid_grant: The code is not valid.` — telling them
|
|
46
57
|
apart is how a code space gets probed.
|
|
47
58
|
|
|
48
59
|
## Wiring `/authorize`
|
|
49
60
|
|
|
50
|
-
The decision is visa's; the page is yours.
|
|
61
|
+
The decision is visa's; the page is yours. The consent page is the one place a
|
|
62
|
+
user hands an application their data, so three things are not optional:
|
|
63
|
+
|
|
64
|
+
- **The consent POST is CSRF-protected.** Without it, a page on another site
|
|
65
|
+
auto-submits the form — its own client, its own PKCE challenge,
|
|
66
|
+
`approve=1` — and a signed-in user grants the attacker's application without
|
|
67
|
+
seeing anything (RFC 6819 §4.4.1.9). Turn on blackhole's CSRF
|
|
68
|
+
(`csrf: true` in `config/blackhole.ts`) and put `{{ csrfField() }}` in the
|
|
69
|
+
form.
|
|
70
|
+
- **The consent page cannot be framed.** A framed page lets another site lay
|
|
71
|
+
its own button over "Allow" (clickjacking, RFC 9700 §4.15). Send
|
|
72
|
+
`X-Frame-Options: DENY` from this page, and `frame-ancestors 'none'` if you
|
|
73
|
+
build its `Content-Security-Policy` yourself.
|
|
74
|
+
- **The POST grants what the page showed, not what the POST says.** The
|
|
75
|
+
validated request stays on the server, in a single-use ticket bound to the
|
|
76
|
+
session and the user. The form carries only the ticket's id.
|
|
51
77
|
|
|
52
78
|
```ts
|
|
53
79
|
// start/routes.ts
|
|
@@ -63,22 +89,55 @@ router.get('/oauth/authorize', async (ctx) => {
|
|
|
63
89
|
}
|
|
64
90
|
if (!ctx.auth.user) return ctx.response.redirect('/login?next=' + encodeURIComponent(ctx.request.url(true)))
|
|
65
91
|
|
|
92
|
+
// Kept server-side: the POST below grants this, whatever it is sent.
|
|
93
|
+
const ticket = visa.consentTicket(outcome.request, ctx.auth.user.id)
|
|
94
|
+
ctx.session.put('visa.consent', ticket)
|
|
95
|
+
|
|
96
|
+
ctx.response.header('x-frame-options', 'DENY')
|
|
66
97
|
return ctx.view.render('oauth/consent', {
|
|
67
98
|
client: outcome.request.client,
|
|
68
99
|
scopes: outcome.request.scopes,
|
|
100
|
+
ticket: ticket.id,
|
|
69
101
|
})
|
|
70
102
|
})
|
|
71
103
|
|
|
104
|
+
// CSRF-protected by blackhole, like every other form POST.
|
|
72
105
|
router.post('/oauth/consent', async (ctx) => {
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
106
|
+
const user = ctx.auth.getUserOrFail()
|
|
107
|
+
// Pulled, not read: a second POST of the same form finds nothing.
|
|
108
|
+
const validated = await visa.redeemConsentTicket(
|
|
109
|
+
ctx.session.pull('visa.consent'),
|
|
110
|
+
ctx.request.input('ticket'),
|
|
111
|
+
user.id,
|
|
112
|
+
)
|
|
113
|
+
if (validated === null) {
|
|
114
|
+
// No ticket, another page's ticket, another user, expired, or a client
|
|
115
|
+
// that changed since the page was shown: start again.
|
|
116
|
+
return ctx.view.render('oauth/error', { error: { error: 'invalid_request' } })
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const url = ctx.request.input('approve') === '1'
|
|
120
|
+
? await visa.grant(validated, user.id)
|
|
121
|
+
: visa.deny(validated)
|
|
78
122
|
return ctx.response.redirect(url)
|
|
79
123
|
})
|
|
80
124
|
```
|
|
81
125
|
|
|
126
|
+
```html
|
|
127
|
+
<!-- resources/views/oauth/consent.inker -->
|
|
128
|
+
<form method="POST" action="/oauth/consent">
|
|
129
|
+
{{ csrfField() }}
|
|
130
|
+
<input type="hidden" name="ticket" value="{{ ticket }}">
|
|
131
|
+
<button name="approve" value="1">Allow</button>
|
|
132
|
+
<button name="approve" value="0">Deny</button>
|
|
133
|
+
</form>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`redeemConsentTicket` validates the request again (a client may have lost a
|
|
137
|
+
scope or a redirect URI meanwhile) and mints nothing: the code exists only once
|
|
138
|
+
`grant` runs. A ticket lasts ten minutes; `consentTicketTtlSeconds` in the
|
|
139
|
+
config changes it.
|
|
140
|
+
|
|
82
141
|
## Registering a client
|
|
83
142
|
|
|
84
143
|
```ts
|
|
@@ -140,11 +199,23 @@ trailing slash is dropped — every endpoint is built by concatenation, so
|
|
|
140
199
|
|
|
141
200
|
## The store
|
|
142
201
|
|
|
143
|
-
`MemoryStore` is for tests and a single development process.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
202
|
+
`MemoryStore` is for tests and a single development process. `AtlasStore`
|
|
203
|
+
(`@c9up/visa/stores/atlas`) runs on the tables of the migration
|
|
204
|
+
`ream configure` writes. Anything else implements `VisaStore`. Two of its
|
|
205
|
+
methods, `consumeAuthorizationCode` and `consumeRefreshToken`, **must be
|
|
206
|
+
atomic**: two requests racing with the same code must not both succeed, and
|
|
207
|
+
that single-use guarantee is what replay detection is built on.
|
|
208
|
+
|
|
209
|
+
`saveClient` is optional, for clients that live in a table you do not own.
|
|
210
|
+
Without it `registerClient` throws, and a server with `registration.enabled`
|
|
211
|
+
refuses to boot rather than answering 500 to every registration.
|
|
212
|
+
|
|
213
|
+
A `visa_clients` table created by visa 0.1.3 or earlier has no
|
|
214
|
+
`secret_expires_at` column, and `AtlasStore` writes it on every client — a
|
|
215
|
+
secret's expiry is enforced from it. Run `ream configure @c9up/visa` again
|
|
216
|
+
before upgrading: your existing `9000_create_visa_tables` is left alone and
|
|
217
|
+
`9001_add_visa_client_secret_expiry` lands beside it; `migration:run` adds the
|
|
218
|
+
column.
|
|
148
219
|
|
|
149
220
|
## What is not here yet
|
|
150
221
|
|
package/dist/VisaManager.d.ts
CHANGED
|
@@ -19,6 +19,28 @@ export interface VisaConfig extends AuthorizeOptions, TokenOptions {
|
|
|
19
19
|
store: VisaStore;
|
|
20
20
|
/** Whether clients may register themselves, and on what terms (RFC 7591). */
|
|
21
21
|
registration?: RegistrationOptions;
|
|
22
|
+
/**
|
|
23
|
+
* How long a consent page may stay open before its answer is refused, in
|
|
24
|
+
* seconds. Ten minutes by default — see {@link VisaManager.consentTicket}.
|
|
25
|
+
*/
|
|
26
|
+
consentTicketTtlSeconds?: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* What the application keeps server-side between the consent page and the
|
|
30
|
+
* POST that answers it — in the session, never in the form.
|
|
31
|
+
*
|
|
32
|
+
* Plain values only, so any session store can hold it: the request as it was
|
|
33
|
+
* validated, not the client record (which carries the secret's hash).
|
|
34
|
+
*/
|
|
35
|
+
export interface ConsentTicket {
|
|
36
|
+
/** Random, 256 bits. The consent form posts it back; nothing else does. */
|
|
37
|
+
id: string;
|
|
38
|
+
/** Who was asked. Another user answering it is refused. */
|
|
39
|
+
userId: string;
|
|
40
|
+
/** Milliseconds since the epoch. */
|
|
41
|
+
expiresAt: number;
|
|
42
|
+
/** The authorization request, rebuilt from what was validated. */
|
|
43
|
+
request: AuthorizationRequest;
|
|
22
44
|
}
|
|
23
45
|
/** What `authorize()` decided. */
|
|
24
46
|
export type AuthorizationOutcome =
|
|
@@ -87,6 +109,31 @@ export declare class VisaManager {
|
|
|
87
109
|
* the answer to it is a POST the application owns.
|
|
88
110
|
*/
|
|
89
111
|
grant(validated: ValidatedRequest, userId: string, now?: Date): Promise<string>;
|
|
112
|
+
/**
|
|
113
|
+
* Remember what the consent page asks, so its answer cannot change it.
|
|
114
|
+
*
|
|
115
|
+
* The application puts the ticket in the user's session, renders its `id`
|
|
116
|
+
* as a hidden field, and on the POST hands both to
|
|
117
|
+
* {@link redeemConsentTicket}. What gets granted is then the request the
|
|
118
|
+
* user was shown — not whatever parameters the POST carries — and the
|
|
119
|
+
* session makes it single use (`session.pull`) and bound to this browser.
|
|
120
|
+
*/
|
|
121
|
+
consentTicket(validated: ValidatedRequest, userId: string, now?: Date): ConsentTicket;
|
|
122
|
+
/**
|
|
123
|
+
* The consent page's answer, checked against the ticket it was rendered with.
|
|
124
|
+
*
|
|
125
|
+
* `ticket` is what the session held — pulled, not read, so a second POST
|
|
126
|
+
* of the same form finds nothing. `presentedId` is the form's hidden field:
|
|
127
|
+
* it must name THIS ticket, which is what stops a form left open in one tab
|
|
128
|
+
* from approving the request another tab put in the session since. The
|
|
129
|
+
* request is validated again — the client may have lost a scope or a
|
|
130
|
+
* redirect URI meanwhile — and no code is minted: that is `grant`'s job,
|
|
131
|
+
* once the user said yes.
|
|
132
|
+
*
|
|
133
|
+
* `null` for anything wrong: no ticket, another ticket, another user,
|
|
134
|
+
* expired, or a request that no longer validates. The user starts again.
|
|
135
|
+
*/
|
|
136
|
+
redeemConsentTicket(ticket: unknown, presentedId: unknown, userId: string, now?: Date): Promise<ValidatedRequest | null>;
|
|
90
137
|
/** The user said no. */
|
|
91
138
|
deny(validated: ValidatedRequest): string;
|
|
92
139
|
token(body: Record<string, unknown>, credentials: ClientCredentials, now?: Date): Promise<TokenResponse>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VisaManager.d.ts","sourceRoot":"","sources":["../src/VisaManager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EAKrB,KAAK,gBAAgB,EAErB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,KAAK,iBAAiB,EAGtB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,UAAU,EAAa,MAAM,aAAa,CAAC;AACpD,OAAO,EAAsB,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EACN,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EAIxB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,KAAK,YAAY,EAAS,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EACX,qBAAqB,EACrB,MAAM,EACN,gBAAgB,EAChB,SAAS,EACT,qBAAqB,EACrB,aAAa,EACb,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,UAAW,SAAQ,gBAAgB,EAAE,YAAY;IACjE,4DAA4D;IAC5D,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IACjB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"VisaManager.d.ts","sourceRoot":"","sources":["../src/VisaManager.ts"],"names":[],"mappings":"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"}
|
package/dist/VisaManager.js
CHANGED
|
@@ -7,11 +7,12 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { errorRedirect, issueAuthorizationCode, successRedirect, UnredirectableError, validateAuthorizationRequest, } from "./authorize.js";
|
|
9
9
|
import { readCredentials, redirectUriMatches, } from "./clients.js";
|
|
10
|
-
import { hashSecret, randomToken } from "./crypto.js";
|
|
10
|
+
import { hashMatches, hashSecret, randomToken, sha256 } from "./crypto.js";
|
|
11
11
|
import { OAuthError, VisaError } from "./errors.js";
|
|
12
12
|
import { introspect, revoke, verifyAccessToken } from "./introspect.js";
|
|
13
13
|
import { registrationResponse, secretExpiryFor, validateRegistration, } from "./register.js";
|
|
14
14
|
import { token } from "./token.js";
|
|
15
|
+
const DEFAULT_CONSENT_TICKET_TTL_SECONDS = 600;
|
|
15
16
|
export class VisaManager {
|
|
16
17
|
#config;
|
|
17
18
|
constructor(config) {
|
|
@@ -19,6 +20,7 @@ export class VisaManager {
|
|
|
19
20
|
// with a broken issuer answers every metadata fetch with something no
|
|
20
21
|
// client can use, and says so nowhere.
|
|
21
22
|
this.#config = { ...config, issuer: normalizeIssuer(config.issuer) };
|
|
23
|
+
assertRegistration(config);
|
|
22
24
|
}
|
|
23
25
|
get issuer() {
|
|
24
26
|
return this.#config.issuer;
|
|
@@ -57,12 +59,11 @@ export class VisaManager {
|
|
|
57
59
|
: { secretExpiresAt: input.secretExpiresAt }),
|
|
58
60
|
};
|
|
59
61
|
const store = this.#config.store;
|
|
60
|
-
if (
|
|
61
|
-
throw
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
store.addClient(client);
|
|
62
|
+
if (store.saveClient === undefined)
|
|
63
|
+
throw readOnlyStore();
|
|
64
|
+
// Awaited: the secret below is handed out once, and handing it out for a
|
|
65
|
+
// client whose write failed is a credential nothing will ever accept.
|
|
66
|
+
await store.saveClient(client);
|
|
66
67
|
return secret === undefined ? { client } : { client, secret };
|
|
67
68
|
}
|
|
68
69
|
/**
|
|
@@ -146,6 +147,81 @@ export class VisaManager {
|
|
|
146
147
|
const code = await issueAuthorizationCode(validated, userId, this.#config.store, this.#config, now);
|
|
147
148
|
return successRedirect(validated, code);
|
|
148
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Remember what the consent page asks, so its answer cannot change it.
|
|
152
|
+
*
|
|
153
|
+
* The application puts the ticket in the user's session, renders its `id`
|
|
154
|
+
* as a hidden field, and on the POST hands both to
|
|
155
|
+
* {@link redeemConsentTicket}. What gets granted is then the request the
|
|
156
|
+
* user was shown — not whatever parameters the POST carries — and the
|
|
157
|
+
* session makes it single use (`session.pull`) and bound to this browser.
|
|
158
|
+
*/
|
|
159
|
+
consentTicket(validated, userId, now = new Date()) {
|
|
160
|
+
const ttl = this.#config.consentTicketTtlSeconds ??
|
|
161
|
+
DEFAULT_CONSENT_TICKET_TTL_SECONDS;
|
|
162
|
+
return {
|
|
163
|
+
id: randomToken(),
|
|
164
|
+
userId,
|
|
165
|
+
expiresAt: now.getTime() + ttl * 1000,
|
|
166
|
+
request: {
|
|
167
|
+
response_type: "code",
|
|
168
|
+
client_id: validated.client.id,
|
|
169
|
+
redirect_uri: validated.redirectUri,
|
|
170
|
+
// Joined from what was resolved, so an omitted `scope` that
|
|
171
|
+
// defaulted to the client's list is the list the user saw, even
|
|
172
|
+
// if the client registers more by the time the user answers.
|
|
173
|
+
scope: validated.scopes.join(" "),
|
|
174
|
+
code_challenge: validated.codeChallenge,
|
|
175
|
+
code_challenge_method: validated.codeChallengeMethod,
|
|
176
|
+
...(validated.state === undefined ? {} : { state: validated.state }),
|
|
177
|
+
...(validated.nonce === undefined ? {} : { nonce: validated.nonce }),
|
|
178
|
+
...(validated.resources.length === 0
|
|
179
|
+
? {}
|
|
180
|
+
: { resource: [...validated.resources] }),
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* The consent page's answer, checked against the ticket it was rendered with.
|
|
186
|
+
*
|
|
187
|
+
* `ticket` is what the session held — pulled, not read, so a second POST
|
|
188
|
+
* of the same form finds nothing. `presentedId` is the form's hidden field:
|
|
189
|
+
* it must name THIS ticket, which is what stops a form left open in one tab
|
|
190
|
+
* from approving the request another tab put in the session since. The
|
|
191
|
+
* request is validated again — the client may have lost a scope or a
|
|
192
|
+
* redirect URI meanwhile — and no code is minted: that is `grant`'s job,
|
|
193
|
+
* once the user said yes.
|
|
194
|
+
*
|
|
195
|
+
* `null` for anything wrong: no ticket, another ticket, another user,
|
|
196
|
+
* expired, or a request that no longer validates. The user starts again.
|
|
197
|
+
*/
|
|
198
|
+
async redeemConsentTicket(ticket, presentedId, userId, now = new Date()) {
|
|
199
|
+
const read = readConsentTicket(ticket);
|
|
200
|
+
if (read === null || typeof presentedId !== "string")
|
|
201
|
+
return null;
|
|
202
|
+
if (!hashMatches(sha256(presentedId), sha256(read.id)))
|
|
203
|
+
return null;
|
|
204
|
+
if (read.userId !== userId)
|
|
205
|
+
return null;
|
|
206
|
+
if (read.expiresAt <= now.getTime())
|
|
207
|
+
return null;
|
|
208
|
+
try {
|
|
209
|
+
const validated = await validateAuthorizationRequest(read.request, this.#config.store, this.#config);
|
|
210
|
+
// An empty `scope` resolves to the client's registered list, which
|
|
211
|
+
// may have grown since the page was shown: the user agreed to the
|
|
212
|
+
// list on the page, and to nothing it has become.
|
|
213
|
+
if (validated.scopes.join(" ") !== (read.request.scope ?? "")) {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
return validated;
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
if (error instanceof UnredirectableError || error instanceof OAuthError) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
throw error;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
149
225
|
/** The user said no. */
|
|
150
226
|
deny(validated) {
|
|
151
227
|
return errorRedirect(validated.redirectUri, new OAuthError("access_denied", "The user refused the request."), validated.state);
|
|
@@ -270,6 +346,92 @@ function normalizeIssuer(issuer) {
|
|
|
270
346
|
}
|
|
271
347
|
return issuer.replace(/\/+$/, "");
|
|
272
348
|
}
|
|
349
|
+
/**
|
|
350
|
+
* A ticket as a session store hands it back: untyped, so read field by field.
|
|
351
|
+
*
|
|
352
|
+
* A session serialises to JSON and back, and a store an application wrote
|
|
353
|
+
* itself may hand back anything — a value that is not exactly a ticket is no
|
|
354
|
+
* ticket.
|
|
355
|
+
*/
|
|
356
|
+
function readConsentTicket(value) {
|
|
357
|
+
if (typeof value !== "object" || value === null)
|
|
358
|
+
return null;
|
|
359
|
+
if (!("id" in value) || typeof value.id !== "string" || value.id === "")
|
|
360
|
+
return null;
|
|
361
|
+
if (!("userId" in value) || typeof value.userId !== "string")
|
|
362
|
+
return null;
|
|
363
|
+
if (!("expiresAt" in value) || typeof value.expiresAt !== "number")
|
|
364
|
+
return null;
|
|
365
|
+
if (!("request" in value))
|
|
366
|
+
return null;
|
|
367
|
+
const request = readTicketRequest(value.request);
|
|
368
|
+
if (request === null)
|
|
369
|
+
return null;
|
|
370
|
+
return {
|
|
371
|
+
id: value.id,
|
|
372
|
+
userId: value.userId,
|
|
373
|
+
expiresAt: value.expiresAt,
|
|
374
|
+
request,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
/** `prompt` is left out on purpose: the ticket IS the consent being asked. */
|
|
378
|
+
const TICKET_STRING_FIELDS = [
|
|
379
|
+
"response_type",
|
|
380
|
+
"client_id",
|
|
381
|
+
"redirect_uri",
|
|
382
|
+
"scope",
|
|
383
|
+
"state",
|
|
384
|
+
"code_challenge",
|
|
385
|
+
"code_challenge_method",
|
|
386
|
+
"nonce",
|
|
387
|
+
];
|
|
388
|
+
function readTicketRequest(value) {
|
|
389
|
+
if (typeof value !== "object" || value === null)
|
|
390
|
+
return null;
|
|
391
|
+
const request = {};
|
|
392
|
+
for (const key of TICKET_STRING_FIELDS) {
|
|
393
|
+
const field = Reflect.get(value, key);
|
|
394
|
+
if (field === undefined)
|
|
395
|
+
continue;
|
|
396
|
+
if (typeof field !== "string")
|
|
397
|
+
return null;
|
|
398
|
+
request[key] = field;
|
|
399
|
+
}
|
|
400
|
+
const resource = Reflect.get(value, "resource");
|
|
401
|
+
if (resource !== undefined) {
|
|
402
|
+
if (!Array.isArray(resource) ||
|
|
403
|
+
!resource.every((entry) => typeof entry === "string")) {
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
request.resource = resource;
|
|
407
|
+
}
|
|
408
|
+
return request;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Registration that can actually register, checked at boot.
|
|
412
|
+
*
|
|
413
|
+
* Both failures would otherwise surface on the first `POST /register`: a store
|
|
414
|
+
* with nowhere to write a client answers every MCP client a 500, and an empty
|
|
415
|
+
* initial access token is matched by `Authorization: Bearer ` — an endpoint
|
|
416
|
+
* the deployment meant to close, open to anyone who sends the header.
|
|
417
|
+
*/
|
|
418
|
+
function assertRegistration(config) {
|
|
419
|
+
const registration = config.registration;
|
|
420
|
+
if (registration?.enabled !== true)
|
|
421
|
+
return;
|
|
422
|
+
if (config.store.saveClient === undefined)
|
|
423
|
+
throw readOnlyStore();
|
|
424
|
+
if (registration.initialAccessToken === "") {
|
|
425
|
+
throw new VisaError("E_VISA_INVALID_INITIAL_ACCESS_TOKEN", "registration.initialAccessToken is empty, which would accept an empty bearer token.", {
|
|
426
|
+
hint: "Set a long random value, or leave it out for open registration.",
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
function readOnlyStore() {
|
|
431
|
+
return new VisaError("E_VISA_STORE_READ_ONLY", "This store cannot register clients; create them where they live.", {
|
|
432
|
+
hint: "Implement saveClient(client) on the store — MemoryStore and AtlasStore both do.",
|
|
433
|
+
});
|
|
434
|
+
}
|
|
273
435
|
/**
|
|
274
436
|
* Every redirect URI a client registers, checked once.
|
|
275
437
|
*
|
package/dist/VisaManager.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VisaManager.js","sourceRoot":"","sources":["../src/VisaManager.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"VisaManager.js","sourceRoot":"","sources":["../src/VisaManager.ts"],"names":[],"mappings":"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"}
|
package/dist/VisaProvider.d.ts
CHANGED
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
* decision; the page around it is yours. The README shows the ten lines.
|
|
15
15
|
*
|
|
16
16
|
* Duck-typed throughout: visa must not import its host's HTTP types.
|
|
17
|
+
*
|
|
18
|
+
* NAMED DEVIATION from the usual `request.all()`: these endpoints read the
|
|
19
|
+
* body only, and refuse a request that puts an OAuth parameter in the query
|
|
20
|
+
* string — see `readBody`.
|
|
17
21
|
*/
|
|
18
22
|
import "./augmentations.js";
|
|
19
23
|
interface VisaContainer {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VisaProvider.d.ts","sourceRoot":"","sources":["../src/VisaProvider.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"VisaProvider.d.ts","sourceRoot":"","sources":["../src/VisaProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,oBAAoB,CAAC;AAW5B,UAAU,aAAa;IACtB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,GAAG,IAAI,CAAC;IACxD,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACjD,GAAG,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;CAC7B;AACD,UAAU,eAAe;IACxB,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;CAC7C;AACD,MAAM,WAAW,cAAc;IAC9B,SAAS,EAAE,aAAa,CAAC;IACzB,MAAM,EAAE,eAAe,CAAC;CACxB;AAwBD,MAAM,CAAC,OAAO,OAAO,YAAY;;IAGpB,SAAS,CAAC,GAAG,EAAE,cAAc;gBAAnB,GAAG,EAAE,cAAc;IAEzC,QAAQ,IAAI,IAAI;IAiBV,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAMrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAiItB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CA8B/B"}
|
package/dist/VisaProvider.js
CHANGED
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
* decision; the page around it is yours. The README shows the ten lines.
|
|
15
15
|
*
|
|
16
16
|
* Duck-typed throughout: visa must not import its host's HTTP types.
|
|
17
|
+
*
|
|
18
|
+
* NAMED DEVIATION from the usual `request.all()`: these endpoints read the
|
|
19
|
+
* body only, and refuse a request that puts an OAuth parameter in the query
|
|
20
|
+
* string — see `readBody`.
|
|
17
21
|
*/
|
|
18
22
|
import "./augmentations.js";
|
|
19
23
|
import { OAuthError } from "./errors.js";
|
|
@@ -52,7 +56,7 @@ export default class VisaProvider {
|
|
|
52
56
|
const prefix = config?.prefix ?? "/oauth";
|
|
53
57
|
router.post(`${prefix}/token`, async (ctx) => {
|
|
54
58
|
await this.#answer(ctx, async () => {
|
|
55
|
-
const body = ctx
|
|
59
|
+
const body = readBody(ctx);
|
|
56
60
|
const credentials = manager.readCredentials({
|
|
57
61
|
body,
|
|
58
62
|
...readAuthorization(ctx),
|
|
@@ -68,7 +72,7 @@ export default class VisaProvider {
|
|
|
68
72
|
});
|
|
69
73
|
router.post(`${prefix}/introspect`, async (ctx) => {
|
|
70
74
|
await this.#answer(ctx, async () => {
|
|
71
|
-
const body = ctx
|
|
75
|
+
const body = readBody(ctx);
|
|
72
76
|
const credentials = manager.readCredentials({
|
|
73
77
|
body,
|
|
74
78
|
...readAuthorization(ctx),
|
|
@@ -79,7 +83,7 @@ export default class VisaProvider {
|
|
|
79
83
|
});
|
|
80
84
|
router.post(`${prefix}/revoke`, async (ctx) => {
|
|
81
85
|
await this.#answer(ctx, async () => {
|
|
82
|
-
const body = ctx
|
|
86
|
+
const body = readBody(ctx);
|
|
83
87
|
const credentials = manager.readCredentials({
|
|
84
88
|
body,
|
|
85
89
|
...readAuthorization(ctx),
|
|
@@ -97,7 +101,7 @@ export default class VisaProvider {
|
|
|
97
101
|
router.post(`${prefix}/register`, async (ctx) => {
|
|
98
102
|
await this.#answer(ctx, async () => {
|
|
99
103
|
const bearer = readBearer(ctx);
|
|
100
|
-
const created = await manager.register(ctx
|
|
104
|
+
const created = await manager.register(readBody(ctx, REGISTRATION_PARAMETERS), bearer);
|
|
101
105
|
// §3.2.1: 201, and the body carries a secret — no cache may
|
|
102
106
|
// keep it.
|
|
103
107
|
ctx.response.status(201);
|
|
@@ -192,13 +196,91 @@ export default class VisaProvider {
|
|
|
192
196
|
}
|
|
193
197
|
}
|
|
194
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* What may never travel in the URL of these endpoints.
|
|
201
|
+
*
|
|
202
|
+
* Every credential and every parameter the spec defines for them: the client's
|
|
203
|
+
* own (§2.3.1, RFC 7523), each grant's (§4), introspection's and revocation's
|
|
204
|
+
* (RFC 7662 §2.1, RFC 7009 §2.1), resource indicators (RFC 8707), a bearer
|
|
205
|
+
* token in its RFC 6750 §2.3 form, and the removed password grant's — a
|
|
206
|
+
* client still sending those sends a password.
|
|
207
|
+
*/
|
|
208
|
+
const OAUTH_PARAMETERS = new Set([
|
|
209
|
+
"client_id",
|
|
210
|
+
"client_secret",
|
|
211
|
+
"client_assertion",
|
|
212
|
+
"client_assertion_type",
|
|
213
|
+
"grant_type",
|
|
214
|
+
"code",
|
|
215
|
+
"code_verifier",
|
|
216
|
+
"redirect_uri",
|
|
217
|
+
"refresh_token",
|
|
218
|
+
"scope",
|
|
219
|
+
"resource",
|
|
220
|
+
"token",
|
|
221
|
+
"token_type_hint",
|
|
222
|
+
"access_token",
|
|
223
|
+
"username",
|
|
224
|
+
"password",
|
|
225
|
+
]);
|
|
226
|
+
/** The same, plus the client metadata a registration carries (RFC 7591 §2). */
|
|
227
|
+
const REGISTRATION_PARAMETERS = new Set([
|
|
228
|
+
...OAUTH_PARAMETERS,
|
|
229
|
+
"redirect_uris",
|
|
230
|
+
"token_endpoint_auth_method",
|
|
231
|
+
"grant_types",
|
|
232
|
+
"response_types",
|
|
233
|
+
"client_name",
|
|
234
|
+
"client_uri",
|
|
235
|
+
"logo_uri",
|
|
236
|
+
"contacts",
|
|
237
|
+
"tos_uri",
|
|
238
|
+
"policy_uri",
|
|
239
|
+
"jwks_uri",
|
|
240
|
+
"jwks",
|
|
241
|
+
"software_id",
|
|
242
|
+
"software_version",
|
|
243
|
+
"software_statement",
|
|
244
|
+
]);
|
|
245
|
+
/**
|
|
246
|
+
* The parameters of a machine endpoint, read from the body and nowhere else.
|
|
247
|
+
*
|
|
248
|
+
* Every one of these requests carries a credential — a client secret, a code,
|
|
249
|
+
* a refresh or access token. RFC 6749 §2.3.1 says client credentials "MUST NOT
|
|
250
|
+
* be included in the request URI", and §3.2, RFC 7009 §2.1, RFC 7662 §2.1 and
|
|
251
|
+
* RFC 7591 §3.1 all define the parameters as a POST body. A URL is kept by
|
|
252
|
+
* access logs, proxies and traces where a body is not.
|
|
253
|
+
*
|
|
254
|
+
* So the query string is never read, and a request that puts an OAuth
|
|
255
|
+
* parameter there is refused rather than answered: accepting it would teach a
|
|
256
|
+
* client that the URL works, and the secret it carries is already in a log.
|
|
257
|
+
* Anything else in the query (a tracing or cache-busting parameter a proxy
|
|
258
|
+
* added) is ignored, not refused.
|
|
259
|
+
*/
|
|
260
|
+
function readBody(ctx, forbidden = OAUTH_PARAMETERS) {
|
|
261
|
+
const inUrl = Object.keys(ctx.request.qs()).filter((key) => forbidden.has(key));
|
|
262
|
+
if (inUrl.length > 0) {
|
|
263
|
+
throw new OAuthError("invalid_request", `OAuth parameters go in the request body, never in the URL: ${inUrl.join(", ")}.`);
|
|
264
|
+
}
|
|
265
|
+
const body = ctx.request.body();
|
|
266
|
+
if (body === undefined || body === null)
|
|
267
|
+
return {};
|
|
268
|
+
if (!isRecord(body)) {
|
|
269
|
+
throw new OAuthError("invalid_request", "The request body must be a form or a JSON object.");
|
|
270
|
+
}
|
|
271
|
+
return body;
|
|
272
|
+
}
|
|
273
|
+
function isRecord(value) {
|
|
274
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
275
|
+
}
|
|
195
276
|
/** The initial access token a registration may carry (RFC 7591 §3). */
|
|
196
277
|
function readBearer(ctx) {
|
|
197
278
|
const header = ctx.request.header("authorization");
|
|
198
279
|
if (header === undefined)
|
|
199
280
|
return undefined;
|
|
200
281
|
const [scheme, value] = header.split(" ");
|
|
201
|
-
|
|
282
|
+
// An empty value is no token at all, not a token that is the empty string.
|
|
283
|
+
if (scheme?.toLowerCase() !== "bearer" || value === undefined || value === "")
|
|
202
284
|
return undefined;
|
|
203
285
|
return value;
|
|
204
286
|
}
|