|
| 1 | +import pkceChallenge from "pkce-challenge"; |
1 | 2 | import { z } from "zod";
|
2 | 3 |
|
3 | 4 | export const OAuthMetadataSchema = z
|
@@ -56,3 +57,28 @@ export async function discoverOAuthMetadata(
|
56 | 57 |
|
57 | 58 | return OAuthMetadataSchema.parse(await response.json());
|
58 | 59 | }
|
| 60 | + |
| 61 | +export async function startAuthorization( |
| 62 | + serverUrl: string | URL, |
| 63 | + { |
| 64 | + metadata, |
| 65 | + redirectUrl, |
| 66 | + }: { metadata: OAuthMetadata; redirectUrl: string | URL }, |
| 67 | +): Promise<{ authorizationUrl: URL; codeVerifier: string }> { |
| 68 | + // Generate PKCE challenge |
| 69 | + const challenge = await pkceChallenge(); |
| 70 | + const codeVerifier = challenge.code_verifier; |
| 71 | + const codeChallenge = challenge.code_challenge; |
| 72 | + |
| 73 | + const authorizationUrl = metadata?.authorization_endpoint |
| 74 | + ? new URL(metadata?.authorization_endpoint) |
| 75 | + : new URL("/authorize", serverUrl); |
| 76 | + |
| 77 | + // TODO: Validate that these parameters are listed as supported in the metadata, if present. |
| 78 | + authorizationUrl.searchParams.set("response_type", "code"); |
| 79 | + authorizationUrl.searchParams.set("code_challenge", codeChallenge); |
| 80 | + authorizationUrl.searchParams.set("code_challenge_method", "S256"); |
| 81 | + authorizationUrl.searchParams.set("redirect_uri", String(redirectUrl)); |
| 82 | + |
| 83 | + return { authorizationUrl, codeVerifier }; |
| 84 | +} |
0 commit comments