@udibo/oauth2 0.17.0 → 0.17.1
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.
|
@@ -117,8 +117,9 @@ export declare function exportSigningKeyJwk(key: SigningKey): Promise<JsonWebKey
|
|
|
117
117
|
}>;
|
|
118
118
|
/**
|
|
119
119
|
* Import a signing key previously exported with {@link exportSigningKeyJwk}.
|
|
120
|
-
* A JWK
|
|
121
|
-
*
|
|
120
|
+
* A JWK that sets a `kid` keeps it. One without a `kid` gets its RFC 7638 JWK
|
|
121
|
+
* thumbprint (base64url SHA-256 of the public key), so every instance
|
|
122
|
+
* importing the same key publishes and stamps the same `kid`.
|
|
122
123
|
*/
|
|
123
124
|
export declare function importSigningKeyJwk(jwk: JsonWebKey & {
|
|
124
125
|
kid?: string;
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { base64urlDecode, base64urlEncode } from "../utils/crypto.js";
|
|
15
15
|
import { snapshotAuthenticationContext } from "../utils/authentication-context.js";
|
|
16
|
+
import { jwkThumbprint } from "../utils/_jwk-thumbprint.js";
|
|
16
17
|
/** A {@link SigningKeyProvider} over one fixed key. */
|
|
17
18
|
export class StaticSigningKeyProvider {
|
|
18
19
|
#key;
|
|
@@ -130,12 +131,13 @@ export async function exportSigningKeyJwk(key) {
|
|
|
130
131
|
}
|
|
131
132
|
/**
|
|
132
133
|
* Import a signing key previously exported with {@link exportSigningKeyJwk}.
|
|
133
|
-
* A JWK
|
|
134
|
-
*
|
|
134
|
+
* A JWK that sets a `kid` keeps it. One without a `kid` gets its RFC 7638 JWK
|
|
135
|
+
* thumbprint (base64url SHA-256 of the public key), so every instance
|
|
136
|
+
* importing the same key publishes and stamps the same `kid`.
|
|
135
137
|
*/
|
|
136
138
|
export async function importSigningKeyJwk(jwk) {
|
|
137
139
|
const privateKey = await crypto.subtle.importKey("jwk", jwk, ES256_PARAMS, true, ["sign"]);
|
|
138
|
-
const kid = jwk.kid ??
|
|
140
|
+
const kid = jwk.kid ?? (await jwkThumbprint(jwk));
|
|
139
141
|
return {
|
|
140
142
|
kid,
|
|
141
143
|
alg: "ES256",
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC 7638 JWK thumbprints.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* The RFC 7638 SHA-256 thumbprint of a JWK, base64url-encoded. Only the key
|
|
8
|
+
* type's required public members are hashed, so a private JWK and its public
|
|
9
|
+
* half share a thumbprint. Rejects with a `TypeError` for a key type other
|
|
10
|
+
* than `EC`, `OKP` or `RSA`, or when a required member is missing.
|
|
11
|
+
*/
|
|
12
|
+
export declare function jwkThumbprint(jwk: JsonWebKey): Promise<string>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC 7638 JWK thumbprints.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { encodeBase64Url } from "./_encoding.js";
|
|
7
|
+
const REQUIRED_MEMBERS = {
|
|
8
|
+
EC: ["crv", "kty", "x", "y"],
|
|
9
|
+
OKP: ["crv", "kty", "x"],
|
|
10
|
+
RSA: ["e", "kty", "n"],
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* The RFC 7638 SHA-256 thumbprint of a JWK, base64url-encoded. Only the key
|
|
14
|
+
* type's required public members are hashed, so a private JWK and its public
|
|
15
|
+
* half share a thumbprint. Rejects with a `TypeError` for a key type other
|
|
16
|
+
* than `EC`, `OKP` or `RSA`, or when a required member is missing.
|
|
17
|
+
*/
|
|
18
|
+
export async function jwkThumbprint(jwk) {
|
|
19
|
+
const members = jwk.kty === undefined ? undefined : REQUIRED_MEMBERS[jwk.kty];
|
|
20
|
+
if (!members) {
|
|
21
|
+
throw new TypeError(`Cannot compute a JWK thumbprint for key type ${JSON.stringify(jwk.kty)}`);
|
|
22
|
+
}
|
|
23
|
+
const fields = jwk;
|
|
24
|
+
const canonical = {};
|
|
25
|
+
for (const member of members) {
|
|
26
|
+
const value = fields[member];
|
|
27
|
+
if (typeof value !== "string") {
|
|
28
|
+
throw new TypeError(`Cannot compute a JWK thumbprint without the "${member}" member`);
|
|
29
|
+
}
|
|
30
|
+
canonical[member] = value;
|
|
31
|
+
}
|
|
32
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(JSON.stringify(canonical)));
|
|
33
|
+
return encodeBase64Url(new Uint8Array(digest));
|
|
34
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@udibo/oauth2",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.1",
|
|
4
4
|
"description": "A flexible OAuth2 toolkit: framework-agnostic authorization & resource servers, a typed client, Hono adapters (including a backend-for-frontend), and React bindings.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"authorization-server",
|