Created
October 9, 2025 12:39
-
-
Save mizchi/cbf25c74eeb9e9bcff8221327f9aceab to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const OPENAI_API_KEY_PATH = "%_%=k"; | |
| const TEMP_PKCE_VERIFIER = "%_%=pk"; | |
| function base64UrlEncode(array: Uint8Array): string { | |
| const base64 = btoa(String.fromCharCode(...array)); | |
| return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); | |
| } | |
| type LoginState = | |
| | { | |
| state: "needLogin"; | |
| } | |
| | { | |
| state: "with-code"; | |
| code: string; | |
| } | |
| | { | |
| state: "ready"; | |
| apiKey: string; | |
| }; | |
| async function main(state: LoginState) { | |
| const root = document.getElementById("root"); | |
| if (!root) { | |
| throw new Error("No root element"); | |
| } | |
| // No login | |
| if (state.state === "needLogin") { | |
| const buf = crypto.getRandomValues(new Uint8Array(32)); | |
| const verifier = base64UrlEncode(buf); | |
| const encoder = new TextEncoder(); | |
| const data = encoder.encode(verifier); | |
| const hashBuffer = await crypto.subtle.digest("SHA-256", data); | |
| const codeChallenge = base64UrlEncode(new Uint8Array(hashBuffer)); | |
| sessionStorage.setItem(TEMP_PKCE_VERIFIER, verifier); | |
| const host = location.protocol.startsWith("https:") | |
| ? `${location.protocol}//${location.host}` | |
| : "localhost:4000"; | |
| const callback_url = `${host}&code_challenge=${codeChallenge}&code_challenge_method=S256`; | |
| const html = ` | |
| <a href="https://openrouter.ai/auth?callback_url=${callback_url}"> | |
| OpenRouter CORS Test | |
| </a>`; | |
| root.innerHTML = html; | |
| } else if (state.state === "with-code") { | |
| // show login link or byok form | |
| const verifier = sessionStorage.getItem(TEMP_PKCE_VERIFIER); | |
| if (!verifier) { | |
| console.error("No code verifier"); | |
| return; | |
| } | |
| const response = await fetch("https://openrouter.ai/api/v1/auth/keys", { | |
| method: "POST", | |
| headers: { | |
| "Content-Type": "application/json", | |
| }, | |
| body: JSON.stringify({ | |
| code: state.code, | |
| code_verifier: verifier, | |
| code_challenge_method: "S256", | |
| }), | |
| }); | |
| const res = (await response.json()) as any; | |
| if (!res.key) { | |
| console.error("Failed to get API Key"); | |
| root.textContent = `Failed to get API Key: ${ | |
| res.error || "Unknown error" | |
| }`; | |
| return; | |
| } | |
| console.log("Got API Key:", res.key); | |
| localStorage.setItem(OPENAI_API_KEY_PATH, res.key); | |
| location.hash = ""; | |
| location.href = "/"; | |
| } else { | |
| // already logged in | |
| // Run your own app with apiKey | |
| } | |
| } | |
| function getLoginState(): LoginState { | |
| const code = new URL(window.location.href).searchParams.get("code"); | |
| if (code) { | |
| return { state: "with-code", code }; | |
| } | |
| const key = localStorage.getItem(OPENAI_API_KEY_PATH); | |
| if (key == null) { | |
| return { state: "needLogin" }; | |
| } | |
| return { state: "ready", apiKey: key }; | |
| } | |
| const state = getLoginState(); | |
| console.log("Login State:", state); | |
| main(state); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment