import { Hono } from "hono"; import * as oauth from "oauth4webapi"; const app = new Hono(); const issuer = new URL("https://fibotree.jp.auth0.com"); const client: oauth.Client = { client_id: "client_id", client_secret: "client_secret-_ejRMnKZks1ykIrGDL7k2X", token_endpoint_auth_method: "client_secret_basic", }; const redirect_uri = "http://localhost:8787/callback"; app.get("/", async (c) => { const as = await oauth .discoveryRequest(issuer) .then((response) => oauth.processDiscoveryResponse(issuer, response)); if (as.code_challenge_methods_supported?.includes("S256") !== true) { // This example assumes S256 PKCE support is signalled // If it isn't supported, random `nonce` must be used for CSRF protection. throw new Error(); } // const code_verifier = oauth.generateRandomCodeVerifier(); const code_verifier = "eQa8h_SDqfrMUQ9GnmJ-5N9vId7ykIs6Oui-_hxxRMo"; const code_challenge = await oauth.calculatePKCECodeChallenge(code_verifier); const code_challenge_method = "S256"; const authorizationUrl = new URL(as.authorization_endpoint!); authorizationUrl.searchParams.set("client_id", client.client_id); authorizationUrl.searchParams.set("code_challenge", code_challenge); authorizationUrl.searchParams.set( "code_challenge_method", code_challenge_method ); authorizationUrl.searchParams.set("redirect_uri", redirect_uri); authorizationUrl.searchParams.set("response_type", "code"); authorizationUrl.searchParams.set("scope", "openid email offline_access"); const signInUrl = authorizationUrl.toString(); return c.html(
); }); app.get("/callback", async (c) => { const as = await oauth .discoveryRequest(issuer) .then((response) => oauth.processDiscoveryResponse(issuer, response)); const currentUrl = new URL(c.req.url); const params = oauth.validateAuthResponse( as, client, currentUrl, oauth.expectNoState ); if (oauth.isOAuth2Error(params)) { console.log("error", params); throw new Error(); // Handle OAuth 2.0 redirect error } const code_verifier = "eQa8h_SDqfrMUQ9GnmJ-5N9vId7ykIs6Oui-_hxxRMo"; const response = await oauth.authorizationCodeGrantRequest( as, client, params, redirect_uri, code_verifier, { additionalParameters: { client_id: "d9zbUT2EZOIAaTcrjlkmsEFAOdgoKPc8", }, } ); let challenges: oauth.WWWAuthenticateChallenge[] | undefined; if ((challenges = oauth.parseWwwAuthenticateChallenges(response))) { for (const challenge of challenges) { console.log("challenge", challenge); } throw new Error(); // Handle www-authenticate challenges as needed } const result = await oauth.processAuthorizationCodeOpenIDResponse( as, client, response ); if (oauth.isOAuth2Error(result)) { console.log("error", result); throw new Error(); // Handle OAuth 2.0 response body error } console.log(result); const { access_token, refresh_token, expires_in } = result; // expires_in: 86400 seconds = 1 day // set cookie with access_token for expires_in // set refresh_token persist, when access_token is empty, use refresh token to refresh const response2 = await oauth.userInfoRequest(as, client, access_token); if ((challenges = oauth.parseWwwAuthenticateChallenges(response2))) { for (const challenge of challenges) { console.log("challenge", challenge); } throw new Error(); // Handle www-authenticate challenges as needed } const claims = oauth.getValidatedIdTokenClaims(result); const { sub } = claims; const result2 = await oauth.processUserInfoResponse( as, client, sub, response2 ); return c.html({JSON.stringify(result2)}