@doist/cli-core 0.18.0 → 0.20.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/CHANGELOG.md +12 -0
- package/README.md +63 -20
- package/dist/auth/errors.d.ts +1 -1
- package/dist/auth/errors.d.ts.map +1 -1
- package/dist/auth/flow.d.ts.map +1 -1
- package/dist/auth/flow.js +7 -8
- package/dist/auth/flow.js.map +1 -1
- package/dist/auth/index.d.ts +7 -3
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +3 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/keyring/internal.d.ts +25 -0
- package/dist/auth/keyring/internal.d.ts.map +1 -1
- package/dist/auth/keyring/internal.js +24 -7
- package/dist/auth/keyring/internal.js.map +1 -1
- package/dist/auth/keyring/token-store.d.ts +7 -1
- package/dist/auth/keyring/token-store.d.ts.map +1 -1
- package/dist/auth/keyring/token-store.js +59 -20
- package/dist/auth/keyring/token-store.js.map +1 -1
- package/dist/auth/persist.d.ts +9 -1
- package/dist/auth/persist.d.ts.map +1 -1
- package/dist/auth/persist.js +20 -0
- package/dist/auth/persist.js.map +1 -1
- package/dist/auth/providers/dcr.d.ts +71 -0
- package/dist/auth/providers/dcr.d.ts.map +1 -0
- package/dist/auth/providers/dcr.js +187 -0
- package/dist/auth/providers/dcr.js.map +1 -0
- package/dist/auth/providers/oauth.d.ts +105 -0
- package/dist/auth/providers/oauth.d.ts.map +1 -0
- package/dist/auth/providers/oauth.js +145 -0
- package/dist/auth/providers/oauth.js.map +1 -0
- package/dist/auth/providers/pkce.d.ts +16 -5
- package/dist/auth/providers/pkce.d.ts.map +1 -1
- package/dist/auth/providers/pkce.js +92 -63
- package/dist/auth/providers/pkce.js.map +1 -1
- package/dist/auth/refresh.d.ts +49 -0
- package/dist/auth/refresh.d.ts.map +1 -0
- package/dist/auth/refresh.js +184 -0
- package/dist/auth/refresh.js.map +1 -0
- package/dist/auth/status.d.ts +12 -4
- package/dist/auth/status.d.ts.map +1 -1
- package/dist/auth/status.js +45 -5
- package/dist/auth/status.js.map +1 -1
- package/dist/auth/types.d.ts +17 -0
- package/dist/auth/types.d.ts.map +1 -1
- package/package.json +9 -4
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { CliError } from '../../errors.js';
|
|
2
2
|
import { accountNotFoundError } from '../user-flag.js';
|
|
3
|
-
import { readAccessTokenForRecord } from './internal.js';
|
|
3
|
+
import { readAccessTokenForRecord, readRefreshTokenForRecord, } from './internal.js';
|
|
4
4
|
import { writeBundleWithKeyringFallback, writeRecordWithKeyringFallback } from './record-write.js';
|
|
5
5
|
import { createSecureStore, DEFAULT_ACCOUNT_FOR_USER, SECURE_STORE_DESCRIPTION, } from './secure-store.js';
|
|
6
6
|
import { refreshAccountSlot } from './slot-naming.js';
|
|
7
7
|
const DEFAULT_MATCH_ACCOUNT = (account, ref) => account.id === ref || account.label === ref;
|
|
8
|
+
function accessReadError(outcome) {
|
|
9
|
+
const message = outcome.reason === 'slot-empty'
|
|
10
|
+
? `${SECURE_STORE_DESCRIPTION} returned no credential for the stored account; the keyring entry may have been removed externally.`
|
|
11
|
+
: outcome.reason === 'slot-unavailable'
|
|
12
|
+
? `${SECURE_STORE_DESCRIPTION} unavailable; could not read stored token (${outcome.detail})`
|
|
13
|
+
: `Access-slot read failed (${outcome.detail})`;
|
|
14
|
+
return new CliError('AUTH_STORE_READ_FAILED', message);
|
|
15
|
+
}
|
|
8
16
|
/**
|
|
9
17
|
* Multi-account `TokenStore` that keeps secrets in the OS credential manager
|
|
10
18
|
* and per-user metadata in the consumer's `UserRecordStore`. Falls back to a
|
|
@@ -132,32 +140,63 @@ export function createKeyringTokenStore(options) {
|
|
|
132
140
|
// best-effort
|
|
133
141
|
}
|
|
134
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Resolve the target record for `ref` (or the implicit default). Shared by
|
|
145
|
+
* `active` / `activeBundle`. The ref-only path skips `getDefaultId()` —
|
|
146
|
+
* `resolveTarget` never consults it when `ref` is supplied, so the extra
|
|
147
|
+
* read would be pure latency on every authenticated command.
|
|
148
|
+
*/
|
|
149
|
+
async function resolveRecord(ref) {
|
|
150
|
+
const snapshot = ref === undefined
|
|
151
|
+
? await readFullSnapshot()
|
|
152
|
+
: { records: await userRecords.list(), defaultId: null };
|
|
153
|
+
return resolveTarget(snapshot, ref);
|
|
154
|
+
}
|
|
135
155
|
return {
|
|
136
156
|
async active(ref) {
|
|
137
|
-
|
|
138
|
-
// touches it when `ref` is supplied, so the extra read would be
|
|
139
|
-
// pure latency on every authenticated command.
|
|
140
|
-
const snapshot = ref === undefined
|
|
141
|
-
? await readFullSnapshot()
|
|
142
|
-
: { records: await userRecords.list(), defaultId: null };
|
|
143
|
-
const record = resolveTarget(snapshot, ref);
|
|
157
|
+
const record = await resolveRecord(ref);
|
|
144
158
|
if (!record)
|
|
145
159
|
return null;
|
|
146
|
-
// Reads the access slot only. Refresh-state material lives in
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
// actually need it (silent refresh).
|
|
160
|
+
// Reads the access slot only. Refresh-state material lives in the
|
|
161
|
+
// keyring + on the record, but `active()` stays cheap and returns
|
|
162
|
+
// the narrow snapshot shape — `activeBundle` lights up the refresh
|
|
163
|
+
// slot only when a caller actually needs it (silent refresh).
|
|
151
164
|
const outcome = await readAccessTokenForRecord(record, secureStoreFor(record.account));
|
|
152
165
|
if (outcome.ok)
|
|
153
166
|
return { token: outcome.token, account: record.account };
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
167
|
+
throw accessReadError(outcome);
|
|
168
|
+
},
|
|
169
|
+
async activeBundle(ref) {
|
|
170
|
+
const record = await resolveRecord(ref);
|
|
171
|
+
if (!record)
|
|
172
|
+
return null;
|
|
173
|
+
// Read both slots in parallel. The refresh side honours the
|
|
174
|
+
// `hasRefreshToken: false` gate inside `readRefreshTokenForRecord`,
|
|
175
|
+
// so an access-only record short-circuits without a refresh-slot
|
|
176
|
+
// IPC. Access-slot failures map to the same typed error as
|
|
177
|
+
// `active()`; a refresh-slot failure degrades silently — the
|
|
178
|
+
// bundle returns without `refreshToken` and the silent-refresh
|
|
179
|
+
// helper translates that to `AUTH_REFRESH_UNAVAILABLE`.
|
|
180
|
+
const [accessOutcome, refreshOutcome] = await Promise.all([
|
|
181
|
+
readAccessTokenForRecord(record, secureStoreFor(record.account)),
|
|
182
|
+
readRefreshTokenForRecord(record, refreshSecureStoreFor(record.account)),
|
|
183
|
+
]);
|
|
184
|
+
if (!accessOutcome.ok)
|
|
185
|
+
throw accessReadError(accessOutcome);
|
|
186
|
+
if (refreshOutcome.ok === false && refreshOutcome.reason === 'slot-error') {
|
|
187
|
+
throw new CliError('AUTH_STORE_READ_FAILED', `Refresh-slot read failed (${refreshOutcome.detail})`);
|
|
188
|
+
}
|
|
189
|
+
const bundle = {
|
|
190
|
+
accessToken: accessOutcome.token,
|
|
191
|
+
...(refreshOutcome.ok ? { refreshToken: refreshOutcome.token } : {}),
|
|
192
|
+
...(record.accessTokenExpiresAt !== undefined
|
|
193
|
+
? { accessTokenExpiresAt: record.accessTokenExpiresAt }
|
|
194
|
+
: {}),
|
|
195
|
+
...(record.refreshTokenExpiresAt !== undefined
|
|
196
|
+
? { refreshTokenExpiresAt: record.refreshTokenExpiresAt }
|
|
197
|
+
: {}),
|
|
198
|
+
};
|
|
199
|
+
return { account: record.account, bundle };
|
|
161
200
|
},
|
|
162
201
|
async set(account, token) {
|
|
163
202
|
// Reset the cached storage result up front so a caller that
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-store.js","sourceRoot":"","sources":["../../../src/auth/keyring/token-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"token-store.js","sourceRoot":"","sources":["../../../src/auth/keyring/token-store.ts"],"names":[],"mappings":"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"}
|
package/dist/auth/persist.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AuthAccount, TokenBundle, TokenStore } from './types.js';
|
|
1
|
+
import type { AuthAccount, ExchangeResult, TokenBundle, TokenStore } from './types.js';
|
|
2
2
|
export type PersistBundleOptions<TAccount extends AuthAccount> = {
|
|
3
3
|
store: TokenStore<TAccount>;
|
|
4
4
|
account: TAccount;
|
|
@@ -19,5 +19,13 @@ export type PersistBundleOptions<TAccount extends AuthAccount> = {
|
|
|
19
19
|
* silent-refresh-safe selection (no re-pinning on background rotation)
|
|
20
20
|
* MUST implement `setBundle`.
|
|
21
21
|
*/
|
|
22
|
+
/**
|
|
23
|
+
* Build a `TokenBundle` from an `ExchangeResult`. `prev` carries the previous
|
|
24
|
+
* refresh token + its expiry forward when the server didn't reissue one (most
|
|
25
|
+
* don't on a refresh-grant). When the server DID return a new refresh token,
|
|
26
|
+
* its expiry is whatever the server gave (or unknown) — never the old token's,
|
|
27
|
+
* which would attach stale expiry metadata to a different credential.
|
|
28
|
+
*/
|
|
29
|
+
export declare function bundleFromExchange<TAccount extends AuthAccount>(exchange: ExchangeResult<TAccount>, prev?: TokenBundle): TokenBundle;
|
|
22
30
|
export declare function persistBundle<TAccount extends AuthAccount>(options: PersistBundleOptions<TAccount>): Promise<void>;
|
|
23
31
|
//# sourceMappingURL=persist.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../../src/auth/persist.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../../src/auth/persist.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAEtF,MAAM,MAAM,oBAAoB,CAAC,QAAQ,SAAS,WAAW,IAAI;IAC7D,KAAK,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;IAC3B,OAAO,EAAE,QAAQ,CAAA;IACjB,MAAM,EAAE,WAAW,CAAA;IACnB,yEAAyE;IACzE,cAAc,CAAC,EAAE,OAAO,CAAA;CAC3B,CAAA;AAED;;;;;;;;;;;;GAYG;AACH;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,SAAS,WAAW,EAC3D,QAAQ,EAAE,cAAc,CAAC,QAAQ,CAAC,EAClC,IAAI,CAAC,EAAE,WAAW,GACnB,WAAW,CAYb;AAED,wBAAsB,aAAa,CAAC,QAAQ,SAAS,WAAW,EAC5D,OAAO,EAAE,oBAAoB,CAAC,QAAQ,CAAC,GACxC,OAAO,CAAC,IAAI,CAAC,CAqBf"}
|
package/dist/auth/persist.js
CHANGED
|
@@ -12,6 +12,26 @@ import { CliError, getErrorMessage } from '../errors.js';
|
|
|
12
12
|
* silent-refresh-safe selection (no re-pinning on background rotation)
|
|
13
13
|
* MUST implement `setBundle`.
|
|
14
14
|
*/
|
|
15
|
+
/**
|
|
16
|
+
* Build a `TokenBundle` from an `ExchangeResult`. `prev` carries the previous
|
|
17
|
+
* refresh token + its expiry forward when the server didn't reissue one (most
|
|
18
|
+
* don't on a refresh-grant). When the server DID return a new refresh token,
|
|
19
|
+
* its expiry is whatever the server gave (or unknown) — never the old token's,
|
|
20
|
+
* which would attach stale expiry metadata to a different credential.
|
|
21
|
+
*/
|
|
22
|
+
export function bundleFromExchange(exchange, prev) {
|
|
23
|
+
const rotatedRefresh = exchange.refreshToken !== undefined;
|
|
24
|
+
const refreshToken = exchange.refreshToken ?? prev?.refreshToken;
|
|
25
|
+
const refreshTokenExpiresAt = rotatedRefresh
|
|
26
|
+
? exchange.refreshTokenExpiresAt
|
|
27
|
+
: (exchange.refreshTokenExpiresAt ?? prev?.refreshTokenExpiresAt);
|
|
28
|
+
return {
|
|
29
|
+
accessToken: exchange.accessToken,
|
|
30
|
+
...(refreshToken !== undefined ? { refreshToken } : {}),
|
|
31
|
+
...(exchange.expiresAt !== undefined ? { accessTokenExpiresAt: exchange.expiresAt } : {}),
|
|
32
|
+
...(refreshTokenExpiresAt !== undefined ? { refreshTokenExpiresAt } : {}),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
15
35
|
export async function persistBundle(options) {
|
|
16
36
|
const { store, account, bundle, promoteDefault } = options;
|
|
17
37
|
try {
|
package/dist/auth/persist.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persist.js","sourceRoot":"","sources":["../../src/auth/persist.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAWxD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAC/B,OAAuC;IAEvC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,OAAO,CAAA;IAC1D,IAAI,CAAC;QACD,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YAClB,6DAA6D;YAC7D,4DAA4D;YAC5D,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;gBAC/B,MAAM,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;YAC1C,CAAC;iBAAM,CAAC;gBACJ,MAAM,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,cAAc,EAAE,CAAC,CAAA;YAC9D,CAAC;QACL,CAAC;aAAM,CAAC;YACJ,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;QAChD,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,IAAI,KAAK,YAAY,QAAQ;YAAE,MAAM,KAAK,CAAA;QAC1C,MAAM,IAAI,QAAQ,CACd,yBAAyB,EACzB,4BAA4B,eAAe,CAAC,KAAK,CAAC,EAAE,CACvD,CAAA;IACL,CAAC;AACL,CAAC"}
|
|
1
|
+
{"version":3,"file":"persist.js","sourceRoot":"","sources":["../../src/auth/persist.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAWxD;;;;;;;;;;;;GAYG;AACH;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAC9B,QAAkC,EAClC,IAAkB;IAElB,MAAM,cAAc,GAAG,QAAQ,CAAC,YAAY,KAAK,SAAS,CAAA;IAC1D,MAAM,YAAY,GAAG,QAAQ,CAAC,YAAY,IAAI,IAAI,EAAE,YAAY,CAAA;IAChE,MAAM,qBAAqB,GAAG,cAAc;QACxC,CAAC,CAAC,QAAQ,CAAC,qBAAqB;QAChC,CAAC,CAAC,CAAC,QAAQ,CAAC,qBAAqB,IAAI,IAAI,EAAE,qBAAqB,CAAC,CAAA;IACrE,OAAO;QACH,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,GAAG,CAAC,QAAQ,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,oBAAoB,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzF,GAAG,CAAC,qBAAqB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,qBAAqB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5E,CAAA;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAC/B,OAAuC;IAEvC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,OAAO,CAAA;IAC1D,IAAI,CAAC;QACD,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YAClB,6DAA6D;YAC7D,4DAA4D;YAC5D,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;gBAC/B,MAAM,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;YAC1C,CAAC;iBAAM,CAAC;gBACJ,MAAM,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,cAAc,EAAE,CAAC,CAAA;YAC9D,CAAC;QACL,CAAC;aAAM,CAAC;YACJ,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;QAChD,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,IAAI,KAAK,YAAY,QAAQ;YAAE,MAAM,KAAK,CAAA;QAC1C,MAAM,IAAI,QAAQ,CACd,yBAAyB,EACzB,4BAA4B,eAAe,CAAC,KAAK,CAAC,EAAE,CACvD,CAAA;IACL,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { AuthAccount, AuthProvider, ValidateInput } from '../types.js';
|
|
2
|
+
import type { OAuthLazyString } from './pkce.js';
|
|
3
|
+
export type DcrTokenEndpointAuthMethod = 'client_secret_basic' | 'client_secret_post' | 'none';
|
|
4
|
+
/**
|
|
5
|
+
* RFC 7591 Dynamic Client Registration metadata POSTed to the registration
|
|
6
|
+
* endpoint. Only fields the CLI typically cares about are named; pass anything
|
|
7
|
+
* else (`software_statement`, `jwks`, …) via `extra`.
|
|
8
|
+
*/
|
|
9
|
+
export type DcrClientMetadata = {
|
|
10
|
+
clientName: string;
|
|
11
|
+
clientUri?: string;
|
|
12
|
+
logoUri?: string;
|
|
13
|
+
applicationType?: 'native' | 'web';
|
|
14
|
+
/**
|
|
15
|
+
* Requested token-endpoint auth method. Defaults to `'client_secret_basic'`.
|
|
16
|
+
* The registration response is authoritative per RFC 7591 §3.2.1 — when
|
|
17
|
+
* the server returns its own `token_endpoint_auth_method`, that value
|
|
18
|
+
* wins over this configured one.
|
|
19
|
+
*/
|
|
20
|
+
tokenEndpointAuthMethod?: DcrTokenEndpointAuthMethod;
|
|
21
|
+
/** Defaults to `['authorization_code']`. */
|
|
22
|
+
grantTypes?: string[];
|
|
23
|
+
/** Defaults to `['code']`. */
|
|
24
|
+
responseTypes?: string[];
|
|
25
|
+
/** Merged verbatim into the registration POST body. */
|
|
26
|
+
extra?: Record<string, unknown>;
|
|
27
|
+
};
|
|
28
|
+
export type DcrProviderOptions<TAccount extends AuthAccount = AuthAccount> = {
|
|
29
|
+
/** RFC 7591 registration endpoint. Function form supports per-flow base URLs. */
|
|
30
|
+
registrationUrl: OAuthLazyString;
|
|
31
|
+
/** OAuth 2.0 authorize endpoint. */
|
|
32
|
+
authorizeUrl: OAuthLazyString;
|
|
33
|
+
/** OAuth 2.0 token endpoint. */
|
|
34
|
+
tokenUrl: OAuthLazyString;
|
|
35
|
+
clientMetadata: DcrClientMetadata;
|
|
36
|
+
/** How to join scopes in the authorize URL. Default `' '` (RFC 6749). */
|
|
37
|
+
scopeSeparator?: string;
|
|
38
|
+
verifierAlphabet?: string;
|
|
39
|
+
/** Default 64. */
|
|
40
|
+
verifierLength?: number;
|
|
41
|
+
/** Probe an authenticated endpoint to confirm the token works and resolve the account. */
|
|
42
|
+
validate: (input: ValidateInput) => Promise<TAccount>;
|
|
43
|
+
/**
|
|
44
|
+
* User-facing remediation hints attached to every CliError this factory
|
|
45
|
+
* throws (`AUTH_DCR_FAILED` from `prepare()` / `authorize()` and
|
|
46
|
+
* `AUTH_TOKEN_EXCHANGE_FAILED` from `exchangeCode()`). Server-returned
|
|
47
|
+
* error details are appended after these so the actionable hint stays
|
|
48
|
+
* first.
|
|
49
|
+
*/
|
|
50
|
+
errorHints?: string[];
|
|
51
|
+
/** Inject a fetch implementation (tests / custom transport). */
|
|
52
|
+
fetchImpl?: typeof fetch;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Build an `AuthProvider` for the RFC 7591 Dynamic Client Registration flow,
|
|
56
|
+
* driven by [`oauth4webapi`](https://github.com/panva/oauth4webapi) (an
|
|
57
|
+
* optional peer dep — installed only by DCR/refresh consumers).
|
|
58
|
+
*
|
|
59
|
+
* - `prepare`: register via `dynamicClientRegistrationRequest`. Stash the
|
|
60
|
+
* issued `client_id`, optional `client_secret`, and the server-returned
|
|
61
|
+
* `token_endpoint_auth_method` (RFC 7591 §3.2.1 — server is authoritative)
|
|
62
|
+
* in the handshake.
|
|
63
|
+
* - `authorize`: standard PKCE S256 with `client_id` read from the handshake.
|
|
64
|
+
* - `exchangeCode`: `authorizationCodeGrantRequest` authenticated per the
|
|
65
|
+
* handshake's server-returned auth method (falling back to the configured
|
|
66
|
+
* one) — `ClientSecretBasic` / `ClientSecretPost` / `None` (the last also
|
|
67
|
+
* when the registration response carried no `client_secret`).
|
|
68
|
+
* - `validateToken`: caller-supplied.
|
|
69
|
+
*/
|
|
70
|
+
export declare function createDcrProvider<TAccount extends AuthAccount>(options: DcrProviderOptions<TAccount>): AuthProvider<TAccount>;
|
|
71
|
+
//# sourceMappingURL=dcr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dcr.d.ts","sourceRoot":"","sources":["../../../src/auth/providers/dcr.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACR,WAAW,EACX,YAAY,EAOZ,aAAa,EAChB,MAAM,aAAa,CAAA;AAQpB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAEhD,MAAM,MAAM,0BAA0B,GAAG,qBAAqB,GAAG,oBAAoB,GAAG,MAAM,CAAA;AAE9F;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,eAAe,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAA;IAClC;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,0BAA0B,CAAA;IACpD,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,8BAA8B;IAC9B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC,CAAA;AAED,MAAM,MAAM,kBAAkB,CAAC,QAAQ,SAAS,WAAW,GAAG,WAAW,IAAI;IACzE,iFAAiF;IACjF,eAAe,EAAE,eAAe,CAAA;IAChC,oCAAoC;IACpC,YAAY,EAAE,eAAe,CAAA;IAC7B,gCAAgC;IAChC,QAAQ,EAAE,eAAe,CAAA;IACzB,cAAc,EAAE,iBAAiB,CAAA;IACjC,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,kBAAkB;IAClB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,0FAA0F;IAC1F,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;IACrD;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,gEAAgE;IAChE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CAC3B,CAAA;AAUD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,SAAS,WAAW,EAC1D,OAAO,EAAE,kBAAkB,CAAC,QAAQ,CAAC,GACtC,YAAY,CAAC,QAAQ,CAAC,CAkLxB"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { getErrorMessage } from '../../errors.js';
|
|
2
|
+
import { deriveChallenge, generateVerifier } from '../pkce.js';
|
|
3
|
+
import { buildAuthError, buildPkceAuthorizeUrl, expiresAtFromExpiresIn, loadOauth4webapi, resolve, } from './oauth.js';
|
|
4
|
+
const MISSING_PEER_HINTS = ['Run `npm install oauth4webapi` in your CLI.'];
|
|
5
|
+
const VALID_AUTH_METHODS = new Set([
|
|
6
|
+
'client_secret_basic',
|
|
7
|
+
'client_secret_post',
|
|
8
|
+
'none',
|
|
9
|
+
]);
|
|
10
|
+
/**
|
|
11
|
+
* Build an `AuthProvider` for the RFC 7591 Dynamic Client Registration flow,
|
|
12
|
+
* driven by [`oauth4webapi`](https://github.com/panva/oauth4webapi) (an
|
|
13
|
+
* optional peer dep — installed only by DCR/refresh consumers).
|
|
14
|
+
*
|
|
15
|
+
* - `prepare`: register via `dynamicClientRegistrationRequest`. Stash the
|
|
16
|
+
* issued `client_id`, optional `client_secret`, and the server-returned
|
|
17
|
+
* `token_endpoint_auth_method` (RFC 7591 §3.2.1 — server is authoritative)
|
|
18
|
+
* in the handshake.
|
|
19
|
+
* - `authorize`: standard PKCE S256 with `client_id` read from the handshake.
|
|
20
|
+
* - `exchangeCode`: `authorizationCodeGrantRequest` authenticated per the
|
|
21
|
+
* handshake's server-returned auth method (falling back to the configured
|
|
22
|
+
* one) — `ClientSecretBasic` / `ClientSecretPost` / `None` (the last also
|
|
23
|
+
* when the registration response carried no `client_secret`).
|
|
24
|
+
* - `validateToken`: caller-supplied.
|
|
25
|
+
*/
|
|
26
|
+
export function createDcrProvider(options) {
|
|
27
|
+
const scopeSeparator = options.scopeSeparator ?? ' ';
|
|
28
|
+
const configuredAuthMethod = options.clientMetadata.tokenEndpointAuthMethod ?? 'client_secret_basic';
|
|
29
|
+
return {
|
|
30
|
+
async prepare(input) {
|
|
31
|
+
const oauth = await loadOauth4webapi({
|
|
32
|
+
code: 'AUTH_DCR_FAILED',
|
|
33
|
+
missingMessage: 'oauth4webapi is required for Dynamic Client Registration.',
|
|
34
|
+
userHints: options.errorHints,
|
|
35
|
+
missingHints: MISSING_PEER_HINTS,
|
|
36
|
+
});
|
|
37
|
+
const registrationUrl = await resolve(options.registrationUrl, {}, input.flags);
|
|
38
|
+
const as = {
|
|
39
|
+
issuer: registrationUrl,
|
|
40
|
+
registration_endpoint: registrationUrl,
|
|
41
|
+
};
|
|
42
|
+
const metadata = buildRegistrationMetadata(options.clientMetadata, input.redirectUri, configuredAuthMethod);
|
|
43
|
+
let client;
|
|
44
|
+
try {
|
|
45
|
+
const response = await oauth.dynamicClientRegistrationRequest(as, metadata, customFetchOptions(oauth, options.fetchImpl));
|
|
46
|
+
client = await oauth.processDynamicClientRegistrationResponse(response);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
throw mapOauthError(error, oauth, 'AUTH_DCR_FAILED', 'Dynamic Client Registration failed.', options.errorHints);
|
|
50
|
+
}
|
|
51
|
+
const handshake = { clientId: client.client_id };
|
|
52
|
+
if (typeof client.client_secret === 'string') {
|
|
53
|
+
handshake.clientSecret = client.client_secret;
|
|
54
|
+
}
|
|
55
|
+
// Per RFC 7591 §3.2.1 the server's chosen method is authoritative.
|
|
56
|
+
// Honour a supported one; fail fast on a method we can't perform
|
|
57
|
+
// (e.g. `private_key_jwt`) rather than silently authenticating the
|
|
58
|
+
// token request with the wrong scheme.
|
|
59
|
+
const serverMethod = client.token_endpoint_auth_method;
|
|
60
|
+
if (typeof serverMethod === 'string') {
|
|
61
|
+
if (!VALID_AUTH_METHODS.has(serverMethod)) {
|
|
62
|
+
throw buildAuthError('AUTH_DCR_FAILED', `Registration server selected an unsupported token_endpoint_auth_method: ${serverMethod}.`, options.errorHints);
|
|
63
|
+
}
|
|
64
|
+
handshake.tokenEndpointAuthMethod = serverMethod;
|
|
65
|
+
}
|
|
66
|
+
return { handshake };
|
|
67
|
+
},
|
|
68
|
+
async authorize(input) {
|
|
69
|
+
const clientId = input.handshake.clientId;
|
|
70
|
+
if (typeof clientId !== 'string') {
|
|
71
|
+
throw buildAuthError('AUTH_DCR_FAILED', 'Internal: DCR handshake missing clientId before authorize.', options.errorHints);
|
|
72
|
+
}
|
|
73
|
+
const verifier = generateVerifier({
|
|
74
|
+
alphabet: options.verifierAlphabet,
|
|
75
|
+
length: options.verifierLength,
|
|
76
|
+
});
|
|
77
|
+
const challenge = deriveChallenge(verifier);
|
|
78
|
+
const authorizeUrl = buildPkceAuthorizeUrl({
|
|
79
|
+
authorizeUrl: await resolve(options.authorizeUrl, input.handshake, input.flags),
|
|
80
|
+
clientId,
|
|
81
|
+
redirectUri: input.redirectUri,
|
|
82
|
+
state: input.state,
|
|
83
|
+
scopes: input.scopes,
|
|
84
|
+
scopeSeparator,
|
|
85
|
+
codeChallenge: challenge,
|
|
86
|
+
});
|
|
87
|
+
return {
|
|
88
|
+
authorizeUrl,
|
|
89
|
+
handshake: { ...input.handshake, codeVerifier: verifier },
|
|
90
|
+
};
|
|
91
|
+
},
|
|
92
|
+
async exchangeCode(input) {
|
|
93
|
+
const verifier = input.handshake.codeVerifier;
|
|
94
|
+
const clientId = input.handshake.clientId;
|
|
95
|
+
if (typeof verifier !== 'string' || typeof clientId !== 'string') {
|
|
96
|
+
throw buildAuthError('AUTH_TOKEN_EXCHANGE_FAILED', 'Internal: DCR handshake state lost between authorize and exchange.', options.errorHints);
|
|
97
|
+
}
|
|
98
|
+
const clientSecretRaw = input.handshake.clientSecret;
|
|
99
|
+
const clientSecret = typeof clientSecretRaw === 'string' ? clientSecretRaw : undefined;
|
|
100
|
+
const issuedMethodRaw = input.handshake.tokenEndpointAuthMethod;
|
|
101
|
+
const issuedMethod = typeof issuedMethodRaw === 'string' &&
|
|
102
|
+
VALID_AUTH_METHODS.has(issuedMethodRaw)
|
|
103
|
+
? issuedMethodRaw
|
|
104
|
+
: undefined;
|
|
105
|
+
// Server-issued method wins (RFC 7591 §3.2.1). Fall back to the
|
|
106
|
+
// configured one only when the server didn't echo a known method.
|
|
107
|
+
const effectiveAuthMethod = issuedMethod ?? configuredAuthMethod;
|
|
108
|
+
const oauth = await loadOauth4webapi({
|
|
109
|
+
code: 'AUTH_TOKEN_EXCHANGE_FAILED',
|
|
110
|
+
missingMessage: 'oauth4webapi is required for the DCR token exchange.',
|
|
111
|
+
userHints: options.errorHints,
|
|
112
|
+
missingHints: MISSING_PEER_HINTS,
|
|
113
|
+
});
|
|
114
|
+
const flags = input.handshake.flags ?? {};
|
|
115
|
+
const tokenUrl = await resolve(options.tokenUrl, input.handshake, flags);
|
|
116
|
+
const as = { issuer: tokenUrl, token_endpoint: tokenUrl };
|
|
117
|
+
const client = { client_id: clientId };
|
|
118
|
+
// Public-client fallback: a registration with no `client_secret`
|
|
119
|
+
// can't authenticate Basic/Post regardless of the requested method,
|
|
120
|
+
// so we POST `client_id` like a non-confidential client. Otherwise
|
|
121
|
+
// honour the effective auth method.
|
|
122
|
+
let clientAuth;
|
|
123
|
+
if (!clientSecret || effectiveAuthMethod === 'none') {
|
|
124
|
+
clientAuth = oauth.None();
|
|
125
|
+
}
|
|
126
|
+
else if (effectiveAuthMethod === 'client_secret_post') {
|
|
127
|
+
clientAuth = oauth.ClientSecretPost(clientSecret);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
clientAuth = oauth.ClientSecretBasic(clientSecret);
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
// The flow runtime owns CSRF state validation; skip oauth4webapi's
|
|
134
|
+
// own state check (it only brands the params for the grant call).
|
|
135
|
+
const callbackParameters = oauth.validateAuthResponse(as, client, new URLSearchParams({ code: input.code }), oauth.skipStateCheck);
|
|
136
|
+
const response = await oauth.authorizationCodeGrantRequest(as, client, clientAuth, callbackParameters, input.redirectUri, verifier, customFetchOptions(oauth, options.fetchImpl));
|
|
137
|
+
const result = await oauth.processAuthorizationCodeResponse(as, client, response);
|
|
138
|
+
return {
|
|
139
|
+
accessToken: result.access_token,
|
|
140
|
+
refreshToken: result.refresh_token,
|
|
141
|
+
expiresAt: expiresAtFromExpiresIn(result.expires_in),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
throw mapOauthError(error, oauth, 'AUTH_TOKEN_EXCHANGE_FAILED', 'Token exchange failed.', options.errorHints);
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
validateToken: options.validate,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/** Thread an injected `fetchImpl` into oauth4webapi via its `customFetch` symbol. */
|
|
152
|
+
function customFetchOptions(oauth, fetchImpl) {
|
|
153
|
+
return fetchImpl ? { [oauth.customFetch]: fetchImpl } : undefined;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Translate an oauth4webapi failure into a typed `CliError`. A `ResponseBodyError`
|
|
157
|
+
* carries the server's OAuth error JSON (`error` / `error_description`) — surface
|
|
158
|
+
* it so a misconfigured server is diagnosable. Everything else (non-conform
|
|
159
|
+
* status, non-JSON body, network failure) collapses to the raw message.
|
|
160
|
+
*/
|
|
161
|
+
function mapOauthError(error, oauth, code, message, hints) {
|
|
162
|
+
if (error instanceof oauth.ResponseBodyError) {
|
|
163
|
+
const detail = error.error_description
|
|
164
|
+
? `${error.error} (${error.error_description})`
|
|
165
|
+
: error.error;
|
|
166
|
+
return buildAuthError(code, message, hints, detail);
|
|
167
|
+
}
|
|
168
|
+
return buildAuthError(code, message, hints, getErrorMessage(error));
|
|
169
|
+
}
|
|
170
|
+
function buildRegistrationMetadata(metadata, redirectUri, tokenEndpointAuthMethod) {
|
|
171
|
+
const body = {
|
|
172
|
+
...metadata.extra,
|
|
173
|
+
client_name: metadata.clientName,
|
|
174
|
+
redirect_uris: [redirectUri],
|
|
175
|
+
grant_types: metadata.grantTypes ?? ['authorization_code'],
|
|
176
|
+
response_types: metadata.responseTypes ?? ['code'],
|
|
177
|
+
token_endpoint_auth_method: tokenEndpointAuthMethod,
|
|
178
|
+
};
|
|
179
|
+
if (metadata.clientUri)
|
|
180
|
+
body.client_uri = metadata.clientUri;
|
|
181
|
+
if (metadata.logoUri)
|
|
182
|
+
body.logo_uri = metadata.logoUri;
|
|
183
|
+
if (metadata.applicationType)
|
|
184
|
+
body.application_type = metadata.applicationType;
|
|
185
|
+
return body;
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=dcr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dcr.js","sourceRoot":"","sources":["../../../src/auth/providers/dcr.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { CliError } from '../../errors.js';
|
|
2
|
+
import type { AuthErrorCode } from '../errors.js';
|
|
3
|
+
import type { OAuthLazyString } from './pkce.js';
|
|
4
|
+
/**
|
|
5
|
+
* Build a `CliError` with user-supplied `errorHints` prepended and an optional
|
|
6
|
+
* server-derived `extra` detail appended. Centralises the "user-actionable
|
|
7
|
+
* first, diagnostic second" ordering used everywhere in this directory.
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildAuthError(code: AuthErrorCode, message: string, userHints: string[] | undefined, extra?: string): CliError;
|
|
10
|
+
/**
|
|
11
|
+
* Resolve a literal-or-function endpoint/clientId against the current handshake
|
|
12
|
+
* and runtime flags. Used by every provider in this directory.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolve(resolver: OAuthLazyString, handshake: Record<string, unknown>, flags: Record<string, unknown>): Promise<string>;
|
|
15
|
+
/** Read a response body without letting a stream error escape — used for hints. */
|
|
16
|
+
export declare function safeReadText(response: Response): Promise<string | undefined>;
|
|
17
|
+
type BuildPkceAuthorizeUrlInput = {
|
|
18
|
+
authorizeUrl: string;
|
|
19
|
+
clientId: string;
|
|
20
|
+
redirectUri: string;
|
|
21
|
+
state: string;
|
|
22
|
+
scopes: string[];
|
|
23
|
+
scopeSeparator: string;
|
|
24
|
+
codeChallenge: string;
|
|
25
|
+
};
|
|
26
|
+
/** Construct the standard PKCE S256 authorize URL. */
|
|
27
|
+
export declare function buildPkceAuthorizeUrl(input: BuildPkceAuthorizeUrlInput): string;
|
|
28
|
+
type PostAndParseJsonInput = {
|
|
29
|
+
url: string;
|
|
30
|
+
headers: Record<string, string>;
|
|
31
|
+
/** Pre-encoded request body. */
|
|
32
|
+
body: string;
|
|
33
|
+
/** Error code wrapped around every failure mode. */
|
|
34
|
+
errorCode: AuthErrorCode;
|
|
35
|
+
/** Prefix for error messages, e.g. `'Token endpoint'` or `'Registration endpoint'`. */
|
|
36
|
+
errorLabel: string;
|
|
37
|
+
errorHints?: string[];
|
|
38
|
+
fetchImpl: typeof fetch;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* POST a request, parse a JSON response, and wrap every failure mode as a
|
|
42
|
+
* typed `CliError`. Common backbone for the OAuth token endpoint and the
|
|
43
|
+
* RFC 7591 dynamic-client-registration endpoint — both POST a body, both
|
|
44
|
+
* expect a JSON reply, both want uniform error handling.
|
|
45
|
+
*
|
|
46
|
+
* Throws `errorCode` with the configured hints on:
|
|
47
|
+
* - network failure (fetch rejection)
|
|
48
|
+
* - non-2xx response (body text appended as a hint after `errorHints`)
|
|
49
|
+
* - non-JSON 2xx body (a misconfigured proxy returning HTML, etc.)
|
|
50
|
+
*
|
|
51
|
+
* Success-shape validation (e.g. `access_token` present) is the caller's
|
|
52
|
+
* job, because it differs per endpoint.
|
|
53
|
+
*/
|
|
54
|
+
export declare function postAndParseJson<T>(input: PostAndParseJsonInput): Promise<T>;
|
|
55
|
+
type PostTokenEndpointInput = {
|
|
56
|
+
url: string;
|
|
57
|
+
/** Form-encoded body. Caller owns grant_type + grant-specific params. */
|
|
58
|
+
body: URLSearchParams;
|
|
59
|
+
/**
|
|
60
|
+
* User-facing remediation hints attached to every `CliError` this helper
|
|
61
|
+
* throws (network failure, non-2xx, parse failure, missing access_token).
|
|
62
|
+
* The server-returned response body (for non-2xx) is appended after these
|
|
63
|
+
* so user hints stay at the top.
|
|
64
|
+
*/
|
|
65
|
+
errorHints?: string[];
|
|
66
|
+
fetchImpl: typeof fetch;
|
|
67
|
+
};
|
|
68
|
+
type PostTokenEndpointResult = {
|
|
69
|
+
accessToken: string;
|
|
70
|
+
refreshToken?: string;
|
|
71
|
+
/** Unix-epoch ms. Computed from `expires_in` when the server returns it. */
|
|
72
|
+
expiresAt?: number;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* POST to an OAuth 2.0 token endpoint and parse the standard JSON response.
|
|
76
|
+
* Covers the public-client `authorization_code` exchange (PKCE) — the caller
|
|
77
|
+
* owns `grant_type` and the grant-specific params via `body`.
|
|
78
|
+
*
|
|
79
|
+
* Failures uniformly throw `CliError('AUTH_TOKEN_EXCHANGE_FAILED', …)`:
|
|
80
|
+
* network errors, non-2xx responses (with body text as a hint), non-JSON
|
|
81
|
+
* bodies, and responses missing `access_token`.
|
|
82
|
+
*/
|
|
83
|
+
export declare function postTokenEndpoint(input: PostTokenEndpointInput): Promise<PostTokenEndpointResult>;
|
|
84
|
+
/** Convert an OAuth `expires_in` (seconds from now) into a Unix-epoch ms deadline. */
|
|
85
|
+
export declare function expiresAtFromExpiresIn(expiresIn: number | undefined): number | undefined;
|
|
86
|
+
type LoadOauthOptions = {
|
|
87
|
+
/** Error code wrapped around a missing/broken peer dep. */
|
|
88
|
+
code: AuthErrorCode;
|
|
89
|
+
/** Message when the peer dep isn't installed. */
|
|
90
|
+
missingMessage: string;
|
|
91
|
+
/** Caller-supplied remediation hints (e.g. provider `errorHints`), prepended first. */
|
|
92
|
+
userHints?: string[];
|
|
93
|
+
/** Install hint for the missing-peer case, appended after `userHints`. */
|
|
94
|
+
missingHints?: string[];
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Lazily import `oauth4webapi`, surfacing a typed `CliError` when the optional
|
|
98
|
+
* peer dep is absent (vs. installed-but-broken). Shared by `createPkceProvider`
|
|
99
|
+
* (refresh) and `createDcrProvider` (registration + token exchange). Caller
|
|
100
|
+
* `userHints` are prepended on both failure branches so the provider's
|
|
101
|
+
* `errorHints` contract holds even when the dep is missing.
|
|
102
|
+
*/
|
|
103
|
+
export declare function loadOauth4webapi(options: LoadOauthOptions): Promise<typeof import('oauth4webapi')>;
|
|
104
|
+
export {};
|
|
105
|
+
//# sourceMappingURL=oauth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../../src/auth/providers/oauth.ts"],"names":[],"mappings":"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"}
|