@jeffjassky/oauth-host 0.1.0 → 0.3.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 +9 -1
- package/dist/index.cjs +96 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +92 -34
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/types/index.d.ts +60 -6
- package/types/test-d.ts +0 -320
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jeffjassky/oauth-host",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "OAuth 2.1 + OIDC authorization server for Express/Mongoose apps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Jeff Jassky <jeff@jeffjassky.com>",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"files": [
|
|
38
38
|
"dist",
|
|
39
|
-
"types",
|
|
39
|
+
"types/index.d.ts",
|
|
40
40
|
"README.md",
|
|
41
41
|
"LICENSE"
|
|
42
42
|
],
|
package/types/index.d.ts
CHANGED
|
@@ -400,9 +400,13 @@ export interface OAuthClientDoc {
|
|
|
400
400
|
name: string;
|
|
401
401
|
/**
|
|
402
402
|
* `public` clients hold no secret and authenticate with `client_id` alone —
|
|
403
|
-
* PKCE is the binding that stands in for it.
|
|
404
|
-
*
|
|
405
|
-
*
|
|
403
|
+
* PKCE is the binding that stands in for it. A `confidential` client can
|
|
404
|
+
* never downgrade itself by omitting its secret.
|
|
405
|
+
*
|
|
406
|
+
* Orthogonal to `registration`: a CIMD row is always public, but a public row
|
|
407
|
+
* is not always CIMD. `clients.create({ type: 'public' })` registers one by
|
|
408
|
+
* hand, which is the only path open to a client that wants PKCE-only and
|
|
409
|
+
* publishes no metadata document (Codex CLI).
|
|
406
410
|
*/
|
|
407
411
|
type: 'confidential' | 'public';
|
|
408
412
|
/**
|
|
@@ -574,16 +578,65 @@ export interface CreateClientSpec {
|
|
|
574
578
|
trusted?: boolean;
|
|
575
579
|
/** Supply a fixed id for a re-provisioned client. Generated when omitted. */
|
|
576
580
|
clientId?: string;
|
|
581
|
+
/**
|
|
582
|
+
* How this client authenticates at `/token`. **Defaults to `confidential`**,
|
|
583
|
+
* so an existing caller is unaffected.
|
|
584
|
+
*
|
|
585
|
+
* `public` generates no secret at all: the registration is `client_id` plus
|
|
586
|
+
* PKCE, `secrets` is empty, and `rotateSecret()` on it throws. Register one
|
|
587
|
+
* for a client that takes a `client_id` and nothing else — Codex CLI's MCP
|
|
588
|
+
* login has `oauth_client_id` and no `oauth_client_secret` field — and cannot
|
|
589
|
+
* use CIMD because it publishes no metadata document.
|
|
590
|
+
*/
|
|
591
|
+
type?: 'confidential' | 'public';
|
|
577
592
|
}
|
|
578
593
|
|
|
579
|
-
|
|
594
|
+
/** What `clients.create({ type: 'confidential' })` and `rotateSecret()` return. */
|
|
595
|
+
export interface CreatedConfidentialClient {
|
|
580
596
|
client: PublicClient;
|
|
581
597
|
clientId: string;
|
|
598
|
+
type: 'confidential';
|
|
582
599
|
/** Returned once. Only its SHA-256 is stored; there is no way to read it back. */
|
|
583
600
|
clientSecret: string;
|
|
584
601
|
}
|
|
585
602
|
|
|
603
|
+
/**
|
|
604
|
+
* What `clients.create({ type: 'public' })` returns.
|
|
605
|
+
*
|
|
606
|
+
* `clientSecret` is declared as `?: undefined` rather than omitted so that
|
|
607
|
+
* `created.clientSecret` still type-checks against the union below — and lands
|
|
608
|
+
* as `string | undefined`, which is what stops a provisioning script printing
|
|
609
|
+
* the word `undefined` into somebody's connector setup screen.
|
|
610
|
+
*/
|
|
611
|
+
export interface CreatedPublicClient {
|
|
612
|
+
client: PublicClient;
|
|
613
|
+
clientId: string;
|
|
614
|
+
type: 'public';
|
|
615
|
+
clientSecret?: undefined;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Discriminated on `type`, not a single interface with an optional secret.
|
|
620
|
+
*
|
|
621
|
+
* The alternative — widening `clientSecret` to `string | undefined` on one
|
|
622
|
+
* shape — reads as source-compatible and is not: `const s: string =
|
|
623
|
+
* created.clientSecret` stops compiling either way. The difference is what
|
|
624
|
+
* happens to the code that does not annotate. With an optional field a
|
|
625
|
+
* provisioning script keeps compiling and prints `undefined`; with a union the
|
|
626
|
+
* caller has to say which kind of registration it asked for before it can reach
|
|
627
|
+
* the secret at all.
|
|
628
|
+
*/
|
|
629
|
+
export type CreatedClient = CreatedConfidentialClient | CreatedPublicClient;
|
|
630
|
+
|
|
586
631
|
export interface ClientsApi {
|
|
632
|
+
/**
|
|
633
|
+
* The overloads exist so the default path keeps its precise type. A spec with
|
|
634
|
+
* no `type` (or `type: 'confidential'`) returns a `clientSecret: string`
|
|
635
|
+
* exactly as before; only a caller that asked for `public`, or that passes a
|
|
636
|
+
* spec whose `type` is not known statically, has to narrow.
|
|
637
|
+
*/
|
|
638
|
+
create(spec: CreateClientSpec & { type: 'public' }): Promise<CreatedPublicClient>;
|
|
639
|
+
create(spec: CreateClientSpec & { type?: 'confidential' }): Promise<CreatedConfidentialClient>;
|
|
587
640
|
create(spec: CreateClientSpec): Promise<CreatedClient>;
|
|
588
641
|
/**
|
|
589
642
|
* Issue a second valid secret and retire the current one after `retireAfter`
|
|
@@ -591,9 +644,10 @@ export interface ClientsApi {
|
|
|
591
644
|
* deployable without downtime.
|
|
592
645
|
*
|
|
593
646
|
* Throws on a **public** client. There is no secret to rotate, and returning
|
|
594
|
-
* one would hand the caller a credential the token endpoint refuses
|
|
647
|
+
* one would hand the caller a credential the token endpoint refuses — which
|
|
648
|
+
* is also why the return type is the confidential member alone.
|
|
595
649
|
*/
|
|
596
|
-
rotateSecret(clientId: string, opts?: { retireAfter?: number; label?: string }): Promise<
|
|
650
|
+
rotateSecret(clientId: string, opts?: { retireAfter?: number; label?: string }): Promise<CreatedConfidentialClient>;
|
|
597
651
|
update(clientId: string, patch: Partial<Omit<CreateClientSpec, 'clientId'>>): Promise<PublicClient>;
|
|
598
652
|
list(query?: { status?: 'active' | 'disabled'; limit?: number; skip?: number }): Promise<{ items: PublicClient[]; limit: number }>;
|
|
599
653
|
get(clientId: string): Promise<PublicClient | null>;
|
package/types/test-d.ts
DELETED
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Compile-only exercise of the public declarations. Never executed — `tsc
|
|
3
|
-
* --noEmit` failing here means the .d.ts files drifted from the source.
|
|
4
|
-
*
|
|
5
|
-
* These declarations are hand-written and the SOURCE IMPORTS THEM, so most
|
|
6
|
-
* drift now fails in `src/` first. This file still earns its place: it is the
|
|
7
|
-
* only thing that checks the surface from OUTSIDE, the way a host consumes it —
|
|
8
|
-
* a type the source never happens to reference can still be wrong here.
|
|
9
|
-
*
|
|
10
|
-
* Hand-written types rot within a day. On featureboard this file immediately
|
|
11
|
-
* caught that `types/` was missing FOUR features added the same afternoon.
|
|
12
|
-
* Every exported symbol must appear below. See standards/traps.md #9.
|
|
13
|
-
*/
|
|
14
|
-
import type {
|
|
15
|
-
ClaimsAdapter,
|
|
16
|
-
ClientBranding,
|
|
17
|
-
ClientIdMetadataConfig,
|
|
18
|
-
ClientSecretRecord,
|
|
19
|
-
ClientsApi,
|
|
20
|
-
ContextsApi,
|
|
21
|
-
CreateClientSpec,
|
|
22
|
-
CreatedClient,
|
|
23
|
-
CreateOAuthHostConfig,
|
|
24
|
-
GrantContext,
|
|
25
|
-
GrantContextAdapter,
|
|
26
|
-
GrantSummary,
|
|
27
|
-
GrantsApi,
|
|
28
|
-
LoadUser,
|
|
29
|
-
Logger,
|
|
30
|
-
ModelNames,
|
|
31
|
-
OAuthAuditDoc,
|
|
32
|
-
OAuthClientDoc,
|
|
33
|
-
OAuthCodeDoc,
|
|
34
|
-
OAuthError,
|
|
35
|
-
OAuthEvent,
|
|
36
|
-
OAuthGrantDoc,
|
|
37
|
-
OAuthHostInstance,
|
|
38
|
-
OAuthHostRouters,
|
|
39
|
-
OAuthKeyDoc,
|
|
40
|
-
OAuthModels,
|
|
41
|
-
OAuthRequestContext,
|
|
42
|
-
OAuthRequestDoc,
|
|
43
|
-
OAuthTokenDoc,
|
|
44
|
-
PackageUser,
|
|
45
|
-
ProtectOptions,
|
|
46
|
-
PublicClient,
|
|
47
|
-
RateLimitConfig,
|
|
48
|
-
RateLimitRule,
|
|
49
|
-
RateLimitStore,
|
|
50
|
-
ResolveUser,
|
|
51
|
-
ResourceSpec,
|
|
52
|
-
ScopeSpec,
|
|
53
|
-
SigningConfig,
|
|
54
|
-
SigningKeySpec,
|
|
55
|
-
TtlConfig,
|
|
56
|
-
UserAdapter,
|
|
57
|
-
UserId,
|
|
58
|
-
UsersApi,
|
|
59
|
-
} from './index.js';
|
|
60
|
-
|
|
61
|
-
declare const oauth: OAuthHostInstance;
|
|
62
|
-
|
|
63
|
-
// ---------------------------------------------------------------------------
|
|
64
|
-
// The degenerate case from plans/build-plan.md §0. If this ever stops
|
|
65
|
-
// compiling as written, the config layer grew a required key the paper test
|
|
66
|
-
// does not pay for.
|
|
67
|
-
// ---------------------------------------------------------------------------
|
|
68
|
-
const minimal: CreateOAuthHostConfig = {
|
|
69
|
-
issuer: 'https://api.example.com',
|
|
70
|
-
resources: [{ id: 'https://api.example.com/mcp', label: 'MCP server' }],
|
|
71
|
-
scopes: [
|
|
72
|
-
{ id: 'openid', label: 'Sign you in', oidc: true },
|
|
73
|
-
{ id: 'contacts.read', label: 'Read your contacts', description: 'Names and emails.' },
|
|
74
|
-
{ id: 'contacts.write', label: 'Create and edit contacts', sensitive: true },
|
|
75
|
-
],
|
|
76
|
-
consentUrl: '/settings/authorize',
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
// Strings are shorthand for `{ id, label: id }` — §0.3.
|
|
80
|
-
const shorthandScopes: CreateOAuthHostConfig = {
|
|
81
|
-
...minimal,
|
|
82
|
-
scopes: ['openid', 'profile', 'email'],
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
// `defaultScopes` is optional and is plain scope ids — deliberately NOT a
|
|
86
|
-
// `ScopeSpec[]`, so it cannot be mistaken for a second catalog.
|
|
87
|
-
const withDefaultScopes: CreateOAuthHostConfig = {
|
|
88
|
-
...minimal,
|
|
89
|
-
defaultScopes: ['openid', 'contacts.read'],
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
// ---------------------------------------------------------------------------
|
|
93
|
-
// Adapters, both forms and both directions.
|
|
94
|
-
// ---------------------------------------------------------------------------
|
|
95
|
-
const withFn: CreateOAuthHostConfig = {
|
|
96
|
-
...minimal,
|
|
97
|
-
resolveUser: () => ({ id: 'abc', email: 'a@b.c', displayName: null }),
|
|
98
|
-
};
|
|
99
|
-
const withAdapter: CreateOAuthHostConfig = {
|
|
100
|
-
...minimal,
|
|
101
|
-
userAdapter: { resolveUser: () => null } satisfies UserAdapter,
|
|
102
|
-
};
|
|
103
|
-
// The second inbound direction. `/userinfo` and the id_token are reached with
|
|
104
|
-
// no host session, so `resolveUser` alone cannot serve profile/email claims.
|
|
105
|
-
const withLoad: CreateOAuthHostConfig = {
|
|
106
|
-
...minimal,
|
|
107
|
-
loadUser: async (id: UserId) => ({ id, email: 'a@b.c', displayName: 'A' }),
|
|
108
|
-
};
|
|
109
|
-
const bothOnAdapter: CreateOAuthHostConfig = {
|
|
110
|
-
...minimal,
|
|
111
|
-
userAdapter: {
|
|
112
|
-
resolveUser: () => null,
|
|
113
|
-
loadUser: (id) => ({ id }),
|
|
114
|
-
} satisfies UserAdapter,
|
|
115
|
-
};
|
|
116
|
-
declare const load: LoadUser;
|
|
117
|
-
void load;
|
|
118
|
-
// Signed-out must be expressible — `/authorize` is a route a signed-out user
|
|
119
|
-
// lands on directly.
|
|
120
|
-
const anon: CreateOAuthHostConfig = { ...minimal, resolveUser: () => null };
|
|
121
|
-
// And async, for a host whose session lookup hits a store.
|
|
122
|
-
const asyncUser: CreateOAuthHostConfig = {
|
|
123
|
-
...minimal,
|
|
124
|
-
resolveUser: async () => null,
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const contextAdapter: GrantContextAdapter = {
|
|
128
|
-
list: (_user, { client, scopes }) => [
|
|
129
|
-
{ id: 'org_1', label: client.name, description: scopes.join(' ') } satisfies GrantContext,
|
|
130
|
-
],
|
|
131
|
-
verify: async (_user, contextId) => contextId.length > 0,
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
const claims: ClaimsAdapter = (user, { scopes, contextId, client }) => ({
|
|
135
|
-
plan: 'pro',
|
|
136
|
-
seen: [user.id, scopes.length, contextId, client.clientId],
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
const tenanted: CreateOAuthHostConfig = {
|
|
140
|
-
...minimal,
|
|
141
|
-
grantContext: contextAdapter,
|
|
142
|
-
claims,
|
|
143
|
-
logger: {} satisfies Logger,
|
|
144
|
-
track: (event: OAuthEvent) => void event.type,
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
// ---------------------------------------------------------------------------
|
|
148
|
-
// Every remaining config key, so a rename in `src/` cannot pass silently.
|
|
149
|
-
// ---------------------------------------------------------------------------
|
|
150
|
-
const tuned: CreateOAuthHostConfig = {
|
|
151
|
-
...minimal,
|
|
152
|
-
mountPath: '/oauth',
|
|
153
|
-
loginUrl: '/login',
|
|
154
|
-
returnParam: 'next',
|
|
155
|
-
ttl: {
|
|
156
|
-
code: 60,
|
|
157
|
-
accessToken: 3600,
|
|
158
|
-
refreshToken: 60 * 86_400,
|
|
159
|
-
refreshAbsolute: 180 * 86_400,
|
|
160
|
-
authorizationRequest: 600,
|
|
161
|
-
} satisfies TtlConfig,
|
|
162
|
-
subjectMode: 'pairwise',
|
|
163
|
-
pairwiseSalt: 'a-permanent-secret',
|
|
164
|
-
signing: {
|
|
165
|
-
autoGenerate: true,
|
|
166
|
-
keys: [{ kid: 'k1', privateKeyPem: '-----BEGIN PRIVATE KEY-----', alg: 'ES256' } satisfies SigningKeySpec],
|
|
167
|
-
} satisfies SigningConfig,
|
|
168
|
-
rateLimits: {
|
|
169
|
-
token: { max: 60, windowMs: 60_000 } satisfies RateLimitRule,
|
|
170
|
-
authorize: false,
|
|
171
|
-
consent: { max: 10, windowMs: 1_000 },
|
|
172
|
-
store: { hit: async () => ({ count: 1, resetAt: Date.now() }) } satisfies RateLimitStore,
|
|
173
|
-
} satisfies RateLimitConfig,
|
|
174
|
-
tokenCache: { ttlMs: 0 },
|
|
175
|
-
modelNames: { client: 'HostOAuthClient', grant: 'HostOAuthGrant' } satisfies ModelNames,
|
|
176
|
-
collectionPrefix: 'oauth_',
|
|
177
|
-
audit: { retentionDays: 400 },
|
|
178
|
-
cors: { tokenEndpoint: false, origins: [] },
|
|
179
|
-
clockSkewMs: 5_000,
|
|
180
|
-
clientIdMetadata: {
|
|
181
|
-
enabled: true,
|
|
182
|
-
allowedHosts: ['claude.ai', '.chatgpt.com'],
|
|
183
|
-
cacheTtlMs: 3_600_000,
|
|
184
|
-
fetchTimeoutMs: 5_000,
|
|
185
|
-
maxBytes: 65_536,
|
|
186
|
-
allowedScopes: ['contacts.read'],
|
|
187
|
-
} satisfies ClientIdMetadataConfig,
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
// `allowedHosts` is required whenever the key is present at all — the type is
|
|
191
|
-
// what stops "enabled, with no allowlist" from compiling in the first place.
|
|
192
|
-
const cimdMinimal: ClientIdMetadataConfig = { allowedHosts: ['claude.ai'] };
|
|
193
|
-
|
|
194
|
-
// A resource may narrow the catalog.
|
|
195
|
-
const narrowed: ResourceSpec = {
|
|
196
|
-
id: 'https://api.example.com/mcp',
|
|
197
|
-
label: 'MCP',
|
|
198
|
-
scopes: ['contacts.read'],
|
|
199
|
-
};
|
|
200
|
-
const scopeSpec: ScopeSpec = { id: 'a', label: 'A', description: 'd', sensitive: true, oidc: false };
|
|
201
|
-
|
|
202
|
-
// ---------------------------------------------------------------------------
|
|
203
|
-
// The instance surface — §2's one screen, checked from outside.
|
|
204
|
-
// ---------------------------------------------------------------------------
|
|
205
|
-
const routers: OAuthHostRouters = oauth.routes;
|
|
206
|
-
void routers.discovery;
|
|
207
|
-
void routers.oauth;
|
|
208
|
-
|
|
209
|
-
// Both call shapes the docs show.
|
|
210
|
-
void oauth.protect('contacts.read');
|
|
211
|
-
void oauth.protect(['a', 'b'], { mode: 'any', resource: 'https://api.example.com/mcp' } satisfies ProtectOptions);
|
|
212
|
-
void oauth.protect();
|
|
213
|
-
|
|
214
|
-
declare const spec: CreateClientSpec;
|
|
215
|
-
async function adminSurface(): Promise<void> {
|
|
216
|
-
const clients: ClientsApi = oauth.clients;
|
|
217
|
-
const created: CreatedClient = await clients.create(spec);
|
|
218
|
-
// The secret is a plain string, returned once. If this ever becomes optional
|
|
219
|
-
// the provisioning script silently stops printing it.
|
|
220
|
-
const secret: string = created.clientSecret;
|
|
221
|
-
void secret;
|
|
222
|
-
await clients.rotateSecret(created.clientId, { retireAfter: 86_400_000, label: 'q3' });
|
|
223
|
-
await clients.update(created.clientId, { name: 'Claude', redirectUris: [] });
|
|
224
|
-
await clients.get(created.clientId);
|
|
225
|
-
await clients.list({ status: 'active', limit: 10, skip: 0 });
|
|
226
|
-
await clients.disable(created.clientId);
|
|
227
|
-
|
|
228
|
-
const grants: GrantsApi = oauth.grants;
|
|
229
|
-
const listed = await grants.list({ userId: 'u1', limit: 10 });
|
|
230
|
-
const summary: GrantSummary = listed.items[0]!;
|
|
231
|
-
void summary.client.branding;
|
|
232
|
-
await grants.revoke(summary.id, { by: 'user' });
|
|
233
|
-
|
|
234
|
-
const users: UsersApi = oauth.users;
|
|
235
|
-
await users.forget('u1');
|
|
236
|
-
await users.revokeAll('u1', { reason: 'password_change' });
|
|
237
|
-
|
|
238
|
-
const contexts: ContextsApi = oauth.contexts;
|
|
239
|
-
await contexts.revoked('u1', 'org_1');
|
|
240
|
-
|
|
241
|
-
await oauth.syncIndexes();
|
|
242
|
-
const models: OAuthModels = oauth.models;
|
|
243
|
-
void models.Client;
|
|
244
|
-
void models.Grant;
|
|
245
|
-
void models.Code;
|
|
246
|
-
void models.Token;
|
|
247
|
-
void models.Request;
|
|
248
|
-
void models.Key;
|
|
249
|
-
void models.Audit;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// ---------------------------------------------------------------------------
|
|
253
|
-
// Documents, as a host would type its own queries against them.
|
|
254
|
-
// ---------------------------------------------------------------------------
|
|
255
|
-
declare const client: OAuthClientDoc;
|
|
256
|
-
declare const grant: OAuthGrantDoc;
|
|
257
|
-
declare const code: OAuthCodeDoc;
|
|
258
|
-
declare const token: OAuthTokenDoc;
|
|
259
|
-
declare const request: OAuthRequestDoc;
|
|
260
|
-
declare const key: OAuthKeyDoc;
|
|
261
|
-
declare const audit: OAuthAuditDoc;
|
|
262
|
-
declare const publicClient: PublicClient;
|
|
263
|
-
declare const branding: ClientBranding;
|
|
264
|
-
declare const secretRecord: ClientSecretRecord;
|
|
265
|
-
declare const user: PackageUser;
|
|
266
|
-
declare const userId: UserId;
|
|
267
|
-
declare const resolve: ResolveUser;
|
|
268
|
-
declare const err: OAuthError;
|
|
269
|
-
|
|
270
|
-
void client.secrets;
|
|
271
|
-
void grant.contextId;
|
|
272
|
-
void code.codeChallengeMethod;
|
|
273
|
-
// The rotation chain has to be reachable from outside, or reuse detection is
|
|
274
|
-
// unverifiable by anyone auditing this package.
|
|
275
|
-
void token.familyId;
|
|
276
|
-
void token.parentId;
|
|
277
|
-
void request.requestId;
|
|
278
|
-
void key.publicJwk;
|
|
279
|
-
void audit.type;
|
|
280
|
-
void publicClient.clientId;
|
|
281
|
-
// A CIMD row must be distinguishable from a hand-registered one from outside —
|
|
282
|
-
// a "connected apps" screen showing both has to be able to say which is which.
|
|
283
|
-
void publicClient.registration;
|
|
284
|
-
void publicClient.metadataUrl;
|
|
285
|
-
void client.registration;
|
|
286
|
-
void client.metadataUrl;
|
|
287
|
-
void client.metadataFetchedAt;
|
|
288
|
-
void client.metadataEtag;
|
|
289
|
-
void branding.logoUrl;
|
|
290
|
-
void secretRecord.retiresAt;
|
|
291
|
-
void user.authTime;
|
|
292
|
-
void userId;
|
|
293
|
-
void resolve;
|
|
294
|
-
void err.code;
|
|
295
|
-
|
|
296
|
-
// The contract `mcp-server` consumes — plan §6 fixes it here.
|
|
297
|
-
declare const reqCtx: OAuthRequestContext;
|
|
298
|
-
void reqCtx.userId;
|
|
299
|
-
void reqCtx.clientId;
|
|
300
|
-
void reqCtx.contextId;
|
|
301
|
-
void reqCtx.scopes;
|
|
302
|
-
void reqCtx.grantId;
|
|
303
|
-
void reqCtx.tokenId;
|
|
304
|
-
void reqCtx.audience;
|
|
305
|
-
|
|
306
|
-
void minimal;
|
|
307
|
-
void shorthandScopes;
|
|
308
|
-
void withDefaultScopes;
|
|
309
|
-
void withFn;
|
|
310
|
-
void withAdapter;
|
|
311
|
-
void withLoad;
|
|
312
|
-
void bothOnAdapter;
|
|
313
|
-
void anon;
|
|
314
|
-
void asyncUser;
|
|
315
|
-
void tenanted;
|
|
316
|
-
void tuned;
|
|
317
|
-
void narrowed;
|
|
318
|
-
void scopeSpec;
|
|
319
|
-
void cimdMinimal;
|
|
320
|
-
void adminSurface;
|