import React, { Fragment, useContext, useEffect, useState } from "react"; import { AuthRequestContext } from "../utils/authrequest"; import { Listbox } from "@headlessui/react"; import { Transition } from "@headlessui/react"; import { ChevronUpDownIcon, CheckIcon } from "@heroicons/react/24/solid"; import clsx from "clsx"; import { Buffer } from "buffer"; import { CopyToClipboard } from "react-copy-to-clipboard"; import BrowserOnly from "@docusaurus/BrowserOnly"; const LinkButton = ({ instance, clientId, redirectUri, responseType, prompt, organizationId, authMethod, codeVerifier, scope, loginHint, idTokenHint, }) => { const [copied, setCopied] = useState(false); return ( { setCopied(true); setTimeout(() => { setCopied(false); }, 2000); }} > ); }; export function SetAuthRequest() { const { instance: [instance, setInstance], clientId: [clientId, setClientId], redirectUri: [redirectUri, setRedirectUri], responseType: [responseType, setResponseType], scope: [scope, setScope], prompt: [prompt, setPrompt], authMethod: [authMethod, setAuthMethod], codeVerifier: [codeVerifier, setCodeVerifier], codeChallenge: [codeChallenge, setCodeChallenge], loginHint: [loginHint, setLoginHint], idTokenHint: [idTokenHint, setIdTokenHint], organizationId: [organizationId, setOrganizationId], } = useContext(AuthRequestContext); const inputClasses = (error) => clsx({ "w-full sm:text-sm h-10 mb-2px rounded-md p-2 bg-input-light-background dark:bg-input-dark-background transition-colors duration-300": true, "border border-solid border-input-light-border dark:border-input-dark-border hover:border-black hover:dark:border-white focus:border-primary-light-500 focus:dark:border-primary-dark-500": true, "focus:outline-none focus:ring-0 text-base text-black dark:text-white placeholder:italic placeholder-gray-700 dark:placeholder-gray-700": true, "border border-warn-light-500 dark:border-warn-dark-500 hover:border-warn-light-500 hover:dark:border-warn-dark-500 focus:border-warn-light-500 focus:dark:border-warn-dark-500": error, }); const labelClasses = "text-sm"; const hintClasses = "mt-1 text-xs text-black/50 dark:text-white/50"; const allResponseTypes = ["code", "id_token", "id_token token"]; const allPrompts = ["", "login", "select_account", "create", "none"]; const allAuthMethods = ["(none) PKCE", "Client Secret Basic"]; const CodeSnipped = ({ cname, children }) => { return {children}; }; const allScopes = [ "openid", "email", "profile", "address", "offline_access", "urn:zitadel:iam:org:project:id:zitadel:aud", "urn:zitadel:iam:user:metadata", `urn:zitadel:iam:org:id:${ organizationId ? organizationId : "[Organization ID]" }`, ]; const [scopeState, setScopeState] = useState( [true, true, true, false, false, false, false, false] // new Array(allScopes.length).fill(false) ); function toggleScope(position, forceChecked = false) { const updatedCheckedState = scopeState.map((item, index) => index === position ? !item : item ); if (forceChecked) { updatedCheckedState[position] = true; } setScopeState(updatedCheckedState); setScope( updatedCheckedState .map((checked, i) => (checked ? allScopes[i] : "")) .filter((s) => !!s) .join(" ") ); } // Encoding functions for code_challenge async function string_to_sha256(message) { // encode as UTF-8 const msgBuffer = new TextEncoder().encode(message); // hash the message const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer); // return ArrayBuffer return hashBuffer; } async function encodeCodeChallenge(codeChallenge) { let arrayBuffer = await string_to_sha256(codeChallenge); let buffer = Buffer.from(arrayBuffer); let base64 = buffer.toString("base64"); let base54url = base64_to_base64url(base64); return base54url; } var base64_to_base64url = function (input) { input = input.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, ""); return input; }; useEffect(async () => { setCodeChallenge(await encodeCodeChallenge(codeVerifier)); }, [codeVerifier]); useEffect(() => { const newScopeState = allScopes.map((s) => scope.includes(s)); if (scopeState !== newScopeState) { setScopeState(newScopeState); } }, [scope]); return (
Your Domain
{() => ( )}
{ const value = event.target.value; setInstance(value); }} /> The domain of your zitadel instance.
Required Parameters
{ const value = event.target.value; setClientId(value); }} /> This is the resource id of an application. It's the application where you want your users to login.
{ const value = event.target.value; setRedirectUri(value); }} /> Must be one of the pre-configured redirect uris for your application.
{responseType} Determines whether a code, id_token token or just id_token will be returned. Most use cases will need code. {allResponseTypes.map((type, typeIdx) => ( `relative cursor-default select-none py-2 pl-10 pr-4 ${ active ? "bg-black/20 dark:bg-white/20" : "" }` } value={type} > {({ selected }) => ( <> {type} {selected ? ( ) : null} )} ))}
{authMethod} Authentication method {allAuthMethods.map((type, typeIdx) => ( `h-10 relative cursor-default select-none py-2 pl-10 pr-4 ${ active ? "bg-black/20 dark:bg-white/20" : "" }` } value={type} > {({ selected }) => ( <> {type} {selected ? ( ) : null} )} ))}
{authMethod === "(none) PKCE" && (
{ const value = event.target.value; setCodeVerifier(value); }} /> Authentication method PKCE requires a random string used to generate a{" "} code_challenge
)}
Additional Parameters
{prompt} Define how the user should be prompted on login and register. {allPrompts.map((type, typeIdx) => ( `h-10 relative cursor-default select-none py-2 pl-10 pr-4 ${ active ? "bg-black/20 dark:bg-white/20" : "" }` } value={type} > {({ selected }) => ( <> {type} {selected ? ( ) : null} )} ))}
{prompt === "select_account" && (
{ const value = event.target.value; setLoginHint(value); }} /> This in combination with a{" "} select_account{" "} prompt the login will preselect a user.
)} {/*
{ const value = event.target.value; setIdTokenHint(value); }} /> This in combination with a{" "} select_account{" "} prompt the login will preselect a user.
*/}
Scopes
{ const value = event.target.value; setOrganizationId(value); allScopes[7] = `urn:zitadel:iam:org:id:${ value ? value : "[Organization ID]" }`; toggleScope(8, true); setScope( scopeState .map((checked, i) => (checked ? allScopes[i] : "")) .filter((s) => !!s) .join(" ") ); }} /> Enforce organization policies and user membership by requesting the{" "} scope{" "} urn:zitadel:iam:org:id:{organizationId}

Scopes

Request additional information about the user with scopes. The claims will be returned on the userinfo_endpoint or in the token (when configured). {allScopes.map((scope, scopeIndex) => { return (
{ toggleScope(scopeIndex); }} />
); })}
{/*
Optional Parameters
{ const value = event.target.value; setIdTokenHint(value); }} />
*/}
Your authorization request
{instance.endsWith("/") ? instance : instance + "/"} oauth/v2/authorize? {`client_id=${encodeURIComponent( clientId )}`} {`&redirect_uri=${encodeURIComponent( redirectUri )}`} {`&response_type=${encodeURIComponent(responseType)}`} {`&scope=${encodeURIComponent( scope )}`} {prompt && ( {`&prompt=${encodeURIComponent( prompt )}`} )} {loginHint && prompt === "select_account" && ( {`&login_hint=${encodeURIComponent( loginHint )}`} )} {authMethod === "(none) PKCE" && ( {`&code_challenge=${encodeURIComponent( codeChallenge )}&code_challenge_method=S256`} )} { window.plausible("OIDC Playground", { props: { method: "Try it out", pageloc: "Authorize" }, }); }} target="_blank" className="mt-2 flex flex-row items-center py-2 px-4 text-white bg-green-500 dark:bg-green-600 hover:dark:bg-green-500 hover:text-white rounded-md hover:no-underline font-semibold text-sm plausible-event-name=OIDC+Playground plausible-event-method=Try+it+out" href={`${ instance.endsWith("/") ? instance : instance + "/" }oauth/v2/authorize?client_id=${encodeURIComponent( clientId )}&redirect_uri=${encodeURIComponent( redirectUri )}&response_type=${encodeURIComponent( responseType )}&scope=${encodeURIComponent(scope)}${ prompt ? `&prompt=${encodeURIComponent(prompt)}` : "" }${ loginHint && prompt === "select_account" ? `&login_hint=${encodeURIComponent(loginHint)}` : "" }${ authMethod === "(none) PKCE" ? `&code_challenge=${encodeURIComponent( codeChallenge )}&code_challenge_method=S256` : "" }`} > Try it out
); }