(
asUrl: string,
opts?: { fetchFn?: FetchLike },
)
| 176 | * §3.3 issuer-mismatch validation (mix-up protection — TODO: upstream to SDK). |
| 177 | */ |
| 178 | export async function discoverAuthorizationServer( |
| 179 | asUrl: string, |
| 180 | opts?: { fetchFn?: FetchLike }, |
| 181 | ): Promise<AuthorizationServerMetadata> { |
| 182 | const meta = await discoverAuthorizationServerMetadata(asUrl, { |
| 183 | fetchFn: opts?.fetchFn ?? defaultFetch, |
| 184 | }) |
| 185 | if (!meta?.issuer || !meta.token_endpoint) { |
| 186 | throw new Error( |
| 187 | `XAA: AS metadata discovery failed: no valid metadata at ${asUrl}`, |
| 188 | ) |
| 189 | } |
| 190 | if (normalizeUrl(meta.issuer) !== normalizeUrl(asUrl)) { |
| 191 | throw new Error( |
| 192 | `XAA: AS metadata discovery failed: issuer mismatch: expected ${asUrl}, got ${meta.issuer}`, |
| 193 | ) |
| 194 | } |
| 195 | // RFC 8414 §3.3 / RFC 9728 §3 require HTTPS. A PRM-advertised http:// AS |
| 196 | // that self-consistently reports an http:// issuer would pass the mismatch |
| 197 | // check above, then we'd POST id_token + client_secret over plaintext. |
| 198 | if (new URL(meta.token_endpoint).protocol !== 'https:') { |
| 199 | throw new Error( |
| 200 | `XAA: refusing non-HTTPS token endpoint: ${meta.token_endpoint}`, |
| 201 | ) |
| 202 | } |
| 203 | return { |
| 204 | issuer: meta.issuer, |
| 205 | token_endpoint: meta.token_endpoint, |
| 206 | grant_types_supported: meta.grant_types_supported, |
| 207 | token_endpoint_auth_methods_supported: |
| 208 | meta.token_endpoint_auth_methods_supported, |
| 209 | } |
| 210 | } |
| 211 | |
| 212 | // ─── Layer 2: Exchange ────────────────────────────────────────────────────── |
| 213 |
no test coverage detected