-
Notifications
You must be signed in to change notification settings - Fork 0
/
raw.ts
110 lines (94 loc) · 3.44 KB
/
raw.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import { OidcDiscoveryOptions } from "./options.ts";
import { RawProviderMetadata } from "./provider-metadata.ts";
/**
* These are the properties that must be present in a valid OIDC metadata response.
*/
const requiredProperties = [
"issuer",
"authorization_endpoint",
"token_endpoint",
"jwks_uri",
"response_types_supported",
"subject_types_supported",
"id_token_signing_alg_values_supported",
];
/**
* Retrieve the raw OIDC provider metadata object for the given issuer. Does not validate
* the response beyond ensuring that it is an object and ensuring that the required properties
* are present. Property value *types* are not checked.
* Throws exceptions from the underlying `fetch()` API, the `AbortSignal` passed in (if any) and
* `TypeError` if the metadata response is not a JSON object.
*
* @param issuer The issuer to be discovered as a string or URL. E.g., "https://accounts.google.com"
* @param options Options to modify retrieval behavior.
*/
export async function retrieveRawProviderMetadata(
issuer: string | URL,
options?: Readonly<OidcDiscoveryOptions>,
): Promise<RawProviderMetadata> {
if (typeof issuer === "string") {
issuer = new URL(issuer);
}
const metadataUrl = new URL(
issuer.href +
(issuer.pathname.endsWith("/")
? ".well-known/openid-configuration"
: "/.well-known/openid-configuration"),
);
const fetchOptions: RequestInit = { credentials: "omit" };
if (options?.signal) {
options.signal.throwIfAborted();
fetchOptions.signal = options.signal;
}
const response = await fetch(metadataUrl, fetchOptions);
if (response.status !== 200) {
throw new Error(
`Incorrect status from metadata endpoint. Expected 200, got ${response.status}`,
);
}
const responseBody = await response.json();
if (
!responseBody || (typeof responseBody !== "object") ||
Array.isArray(responseBody)
) {
throw new TypeError("Provider metadata is not an object");
}
for (const key of requiredProperties) {
if (responseBody[key] === undefined) {
throw new TypeError(
`Required OIDC metadata response property "${key}" is missing`,
);
}
}
const rawMetadata = responseBody as RawProviderMetadata;
// Set the metadata default values, if requested.
if (options?.setDefaults) {
if (rawMetadata.response_modes_supported === undefined) {
rawMetadata.response_modes_supported = ["query", "fragment"];
}
if (rawMetadata.grant_types_supported === undefined) {
rawMetadata.grant_types_supported = ["authorization_code", "implicit"];
}
if (rawMetadata.token_endpoint_auth_methods_supported === undefined) {
rawMetadata.token_endpoint_auth_methods_supported = [
"client_secret_basic",
];
}
if (rawMetadata.claim_types_supported === undefined) {
rawMetadata.claim_types_supported = ["normal"];
}
if (rawMetadata.claims_parameter_supported === undefined) {
rawMetadata.claims_parameter_supported = false;
}
if (rawMetadata.request_parameter_supported === undefined) {
rawMetadata.request_parameter_supported = false;
}
if (rawMetadata.request_uri_parameter_supported === undefined) {
rawMetadata.request_uri_parameter_supported = true; // Yes, the standard says it defaults to `true`.
}
if (rawMetadata.require_request_uri_registration === undefined) {
rawMetadata.require_request_uri_registration = false;
}
}
return rawMetadata;
}