@keycardai/oauth 0.19.0 → 0.21.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 +65 -4
- package/dist/cjs/discovery.d.ts +21 -0
- package/dist/cjs/discovery.d.ts.map +1 -1
- package/dist/cjs/discovery.js +8 -0
- package/dist/cjs/discovery.js.map +1 -1
- package/dist/cjs/errors.d.ts +17 -0
- package/dist/cjs/errors.d.ts.map +1 -1
- package/dist/cjs/errors.js +26 -1
- package/dist/cjs/errors.js.map +1 -1
- package/dist/cjs/index.d.ts +5 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +8 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/pkce.d.ts +5 -0
- package/dist/cjs/pkce.d.ts.map +1 -1
- package/dist/cjs/pkce.js +4 -1
- package/dist/cjs/pkce.js.map +1 -1
- package/dist/cjs/server/eksWorkloadIdentity.d.ts +7 -6
- package/dist/cjs/server/eksWorkloadIdentity.d.ts.map +1 -1
- package/dist/cjs/server/eksWorkloadIdentity.js +11 -95
- package/dist/cjs/server/eksWorkloadIdentity.js.map +1 -1
- package/dist/cjs/server/index.d.ts +2 -0
- package/dist/cjs/server/index.d.ts.map +1 -1
- package/dist/cjs/server/index.js +13 -1
- package/dist/cjs/server/index.js.map +1 -1
- package/dist/cjs/server/workloadIdentity.d.ts +166 -0
- package/dist/cjs/server/workloadIdentity.d.ts.map +1 -0
- package/dist/cjs/server/workloadIdentity.js +355 -0
- package/dist/cjs/server/workloadIdentity.js.map +1 -0
- package/dist/cjs/tokenExchange.d.ts +6 -0
- package/dist/cjs/tokenExchange.d.ts.map +1 -1
- package/dist/cjs/tokenExchange.js +2 -0
- package/dist/cjs/tokenExchange.js.map +1 -1
- package/dist/cjs/userinfo.d.ts +35 -0
- package/dist/cjs/userinfo.d.ts.map +1 -0
- package/dist/cjs/userinfo.js +79 -0
- package/dist/cjs/userinfo.js.map +1 -0
- package/dist/cjs/webApp.d.ts +78 -0
- package/dist/cjs/webApp.d.ts.map +1 -0
- package/dist/cjs/webApp.js +95 -0
- package/dist/cjs/webApp.js.map +1 -0
- package/dist/esm/discovery.d.ts +21 -0
- package/dist/esm/discovery.d.ts.map +1 -1
- package/dist/esm/discovery.js +8 -0
- package/dist/esm/discovery.js.map +1 -1
- package/dist/esm/errors.d.ts +17 -0
- package/dist/esm/errors.d.ts.map +1 -1
- package/dist/esm/errors.js +23 -0
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/index.d.ts +5 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +3 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/pkce.d.ts +5 -0
- package/dist/esm/pkce.d.ts.map +1 -1
- package/dist/esm/pkce.js +4 -1
- package/dist/esm/pkce.js.map +1 -1
- package/dist/esm/server/eksWorkloadIdentity.d.ts +7 -6
- package/dist/esm/server/eksWorkloadIdentity.d.ts.map +1 -1
- package/dist/esm/server/eksWorkloadIdentity.js +11 -62
- package/dist/esm/server/eksWorkloadIdentity.js.map +1 -1
- package/dist/esm/server/index.d.ts +2 -0
- package/dist/esm/server/index.d.ts.map +1 -1
- package/dist/esm/server/index.js +1 -0
- package/dist/esm/server/index.js.map +1 -1
- package/dist/esm/server/workloadIdentity.d.ts +166 -0
- package/dist/esm/server/workloadIdentity.d.ts.map +1 -0
- package/dist/esm/server/workloadIdentity.js +312 -0
- package/dist/esm/server/workloadIdentity.js.map +1 -0
- package/dist/esm/tokenExchange.d.ts +6 -0
- package/dist/esm/tokenExchange.d.ts.map +1 -1
- package/dist/esm/tokenExchange.js +2 -0
- package/dist/esm/tokenExchange.js.map +1 -1
- package/dist/esm/userinfo.d.ts +35 -0
- package/dist/esm/userinfo.d.ts.map +1 -0
- package/dist/esm/userinfo.js +76 -0
- package/dist/esm/userinfo.js.map +1 -0
- package/dist/esm/webApp.d.ts +78 -0
- package/dist/esm/webApp.d.ts.map +1 -0
- package/dist/esm/webApp.js +88 -0
- package/dist/esm/webApp.js.map +1 -0
- package/package.json +12 -2
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import base64url from "./base64url.js";
|
|
2
|
+
import { fetchAuthorizationServerMetadata } from "./discovery.js";
|
|
3
|
+
import { AuthorizationDeniedError, OAuthError, StateMismatchError } from "./errors.js";
|
|
4
|
+
import { buildAuthorizeUrl, exchangeAuthorizationCode, generatePkcePair } from "./pkce.js";
|
|
5
|
+
/**
|
|
6
|
+
* Begin a web-app authorization-code-with-PKCE flow.
|
|
7
|
+
*
|
|
8
|
+
* For applications that own a registered redirect URI and receive the callback
|
|
9
|
+
* on their own route, where the loopback listener `authenticate()` runs is
|
|
10
|
+
* wrong. Generates the PKCE pair and a CSRF `state`, resolves the
|
|
11
|
+
* `authorization_endpoint` by discovery, and builds the authorization URL with
|
|
12
|
+
* one `resource` parameter per entry of `resources`.
|
|
13
|
+
*
|
|
14
|
+
* The SDK holds no state between begin and complete: where `state` and
|
|
15
|
+
* `codeVerifier` live between the redirect and the callback (a session, a
|
|
16
|
+
* signed cookie) is the application's concern, which is what makes the flow
|
|
17
|
+
* safe under concurrent sign-ins and multi-process servers.
|
|
18
|
+
*/
|
|
19
|
+
export async function beginAuthorization(issuer, options) {
|
|
20
|
+
const metadata = options.metadata
|
|
21
|
+
?? await fetchAuthorizationServerMetadata(issuer, { signal: options.signal });
|
|
22
|
+
if (!metadata.authorization_endpoint) {
|
|
23
|
+
throw new Error(`Authorization server "${issuer}" does not advertise an authorization_endpoint`);
|
|
24
|
+
}
|
|
25
|
+
const { codeVerifier, codeChallenge } = await generatePkcePair("S256");
|
|
26
|
+
const stateBytes = new Uint8Array(32);
|
|
27
|
+
crypto.getRandomValues(stateBytes);
|
|
28
|
+
const state = base64url.encode(stateBytes.buffer);
|
|
29
|
+
const resources = [...options.resources ?? []];
|
|
30
|
+
const url = buildAuthorizeUrl(metadata.authorization_endpoint, {
|
|
31
|
+
clientId: options.clientId,
|
|
32
|
+
redirectUri: options.redirectUri,
|
|
33
|
+
codeChallenge,
|
|
34
|
+
state,
|
|
35
|
+
scope: options.scopes && options.scopes.length > 0 ? options.scopes.join(" ") : undefined,
|
|
36
|
+
resources,
|
|
37
|
+
});
|
|
38
|
+
return { url, state, codeVerifier, resources };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Complete a web-app authorization-code-with-PKCE flow from the callback route.
|
|
42
|
+
*
|
|
43
|
+
* Callback validation happens before discovery or any token request: a
|
|
44
|
+
* callback carrying `error` throws `AuthorizationDeniedError`, a missing or
|
|
45
|
+
* non-matching `state` throws `StateMismatchError`, and a missing `code`
|
|
46
|
+
* throws `OAuthError("invalid_request")`.
|
|
47
|
+
*
|
|
48
|
+
* No RFC 8707 `resource` parameter is sent on the token request: the
|
|
49
|
+
* authorization server derives the issued token's audience from the
|
|
50
|
+
* authorization code, which already records the resources authorized at the
|
|
51
|
+
* begin step.
|
|
52
|
+
*/
|
|
53
|
+
export async function completeAuthorization(issuer, options) {
|
|
54
|
+
const params = options.callbackParams instanceof URLSearchParams
|
|
55
|
+
? options.callbackParams
|
|
56
|
+
: new URLSearchParams(options.callbackParams);
|
|
57
|
+
const error = params.get("error");
|
|
58
|
+
if (error) {
|
|
59
|
+
throw new AuthorizationDeniedError(error, params.get("error_description") ?? undefined, params.get("error_uri") ?? undefined);
|
|
60
|
+
}
|
|
61
|
+
const callbackState = params.get("state");
|
|
62
|
+
if (callbackState === null || !timingSafeEqual(callbackState, options.state)) {
|
|
63
|
+
throw new StateMismatchError();
|
|
64
|
+
}
|
|
65
|
+
const code = params.get("code");
|
|
66
|
+
if (!code) {
|
|
67
|
+
throw new OAuthError("invalid_request", "Authorization callback is missing 'code'");
|
|
68
|
+
}
|
|
69
|
+
return exchangeAuthorizationCode(issuer, code, {
|
|
70
|
+
codeVerifier: options.codeVerifier,
|
|
71
|
+
redirectUri: options.redirectUri,
|
|
72
|
+
clientId: options.clientId,
|
|
73
|
+
clientSecret: options.clientSecret,
|
|
74
|
+
metadata: options.metadata,
|
|
75
|
+
signal: options.signal,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/** Compare two strings without leaking their common prefix length via timing. */
|
|
79
|
+
function timingSafeEqual(a, b) {
|
|
80
|
+
const left = new TextEncoder().encode(a);
|
|
81
|
+
const right = new TextEncoder().encode(b);
|
|
82
|
+
let diff = left.length ^ right.length;
|
|
83
|
+
for (let i = 0; i < left.length; i++) {
|
|
84
|
+
diff |= left[i] ^ right[i % (right.length || 1)];
|
|
85
|
+
}
|
|
86
|
+
return diff === 0;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=webApp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webApp.js","sourceRoot":"","sources":["../../src/webApp.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keycardai/oauth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"description": "[Preview] OAuth 2.0 primitives for Keycard: JWKS keyring, JWT signing/verification, server-tier token verifier, AccessContext, ClientSecret credentials, and impersonation via RFC 8693 token exchange",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -94,6 +94,16 @@
|
|
|
94
94
|
"import": "./dist/esm/pkce.js",
|
|
95
95
|
"require": "./dist/cjs/pkce.js",
|
|
96
96
|
"types": "./dist/esm/pkce.d.ts"
|
|
97
|
+
},
|
|
98
|
+
"./webApp": {
|
|
99
|
+
"import": "./dist/esm/webApp.js",
|
|
100
|
+
"require": "./dist/cjs/webApp.js",
|
|
101
|
+
"types": "./dist/esm/webApp.d.ts"
|
|
102
|
+
},
|
|
103
|
+
"./userinfo": {
|
|
104
|
+
"import": "./dist/esm/userinfo.js",
|
|
105
|
+
"require": "./dist/cjs/userinfo.js",
|
|
106
|
+
"types": "./dist/esm/userinfo.d.ts"
|
|
97
107
|
}
|
|
98
108
|
},
|
|
99
109
|
"files": [
|
|
@@ -119,7 +129,7 @@
|
|
|
119
129
|
"@jest/globals": "^30.0.4",
|
|
120
130
|
"@types/node": "^25.6.0",
|
|
121
131
|
"jest": "^30.0.4",
|
|
122
|
-
"ts-jest": "^29.4.
|
|
132
|
+
"ts-jest": "^29.4.7",
|
|
123
133
|
"typescript": "^5.8.3"
|
|
124
134
|
},
|
|
125
135
|
"scripts": {
|