mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 23:37:32 +00:00
docs: add tailwindcss for styles, oidc authorize endpoint playground (#4707)
* variable parser * rm plugin * set fcn * env * EnvCode component * cleanup env demo * env * rm remark plugin * auth request context * auth req component * authorize endpoint construction * rev react page * fix endpoint * styling * query params with anchor * desc * tailwind coexistence * fix styles * add login_hint, organizationId scope * auth request without prompt * show login_hint * sync displayed url with actual href * fix fcn * coloring * Update docs/src/components/authrequest.jsx Co-authored-by: mffap <mpa@zitadel.com> * Update docs/src/components/authrequest.jsx Co-authored-by: mffap <mpa@zitadel.com> * Update docs/src/components/authrequest.jsx Co-authored-by: mffap <mpa@zitadel.com> * Update docs/src/components/authrequest.jsx Co-authored-by: mffap <mpa@zitadel.com> * Update docs/src/components/authrequest.jsx Co-authored-by: mffap <mpa@zitadel.com> * Update docs/src/components/authrequest.jsx Co-authored-by: mffap <mpa@zitadel.com> * add plausible, header * add pkce * move * adds pkce code challenge * replace cboa * reaname and move to required * fall back to cboa due to webpack error * trailing slash * reorder org_id * remove resourceowner * texts * update references * buffer, fix some react dom components * Apply suggestions from code review Co-authored-by: Florian Forster <florian@zitadel.com> * standard scopes Co-authored-by: mffap <mpa@zitadel.com> Co-authored-by: Florian Forster <florian@zitadel.com>
This commit is contained in:
@@ -1,34 +1,32 @@
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
|
||||
import styles from '../css/apicard.module.css';
|
||||
import styles from "../css/apicard.module.css";
|
||||
|
||||
export function ApiCard({ title, type, label, children}) {
|
||||
let style = styles.apiauth;
|
||||
export function ApiCard({ type, children }) {
|
||||
let classes = "";
|
||||
switch (type) {
|
||||
case 'AUTH':
|
||||
style = styles.apiauth;
|
||||
case "AUTH":
|
||||
classes = "bg-green-500/10 dark:bg-green-500/20";
|
||||
break;
|
||||
case 'MGMT':
|
||||
style = styles.apimgmt;
|
||||
case "MGMT":
|
||||
classes = "bg-blue-500/10 dark:bg-blue-500/20";
|
||||
break;
|
||||
case 'ADMIN':
|
||||
style = styles.apiadmin;
|
||||
case "ADMIN":
|
||||
classes = "bg-red-500/10 dark:bg-red-500/20";
|
||||
break;
|
||||
case 'SYSTEM':
|
||||
style = styles.apisystem;
|
||||
case "SYSTEM":
|
||||
classes = "bg-yellow-500/10 dark:bg-yellow-500/20";
|
||||
break;
|
||||
case "ASSET":
|
||||
classes = "bg-black/10 dark:bg-black/20";
|
||||
break;
|
||||
case 'ASSET':
|
||||
style = styles.apiasset;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className={`${styles.apicard} ${style} `}>
|
||||
{/* {title && <h2 className={styles.apicard.title}>{title}</h2>} */}
|
||||
{/* <p className={styles.apicard.description}>
|
||||
|
||||
</p> */}
|
||||
<div
|
||||
className={`${styles.apicard} flex mb-4 flex-row p-4 rounded-lg ${classes} `}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
594
docs/src/components/authrequest.jsx
Normal file
594
docs/src/components/authrequest.jsx
Normal file
@@ -0,0 +1,594 @@
|
||||
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";
|
||||
|
||||
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"];
|
||||
|
||||
const allAuthMethods = ["(none) PKCE", "Client Secret Basic"];
|
||||
|
||||
const CodeSnipped = ({ cname, children }) => {
|
||||
return <span className={cname}>{children}</span>;
|
||||
};
|
||||
|
||||
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 : "[organizationId]"
|
||||
}`,
|
||||
];
|
||||
|
||||
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 (
|
||||
<div className="bg-white/5 rounded-md p-6 shadow">
|
||||
<h5 className="text-lg mt-0 mb-4 font-semibold">Your Domain</h5>
|
||||
<div className="flex flex-col">
|
||||
<label className={`${labelClasses} text-yellow-500`}>
|
||||
Instance Domain
|
||||
</label>
|
||||
<input
|
||||
className={inputClasses(false)}
|
||||
id="instance"
|
||||
value={instance}
|
||||
onChange={(event) => {
|
||||
const value = event.target.value;
|
||||
setInstance(value);
|
||||
}}
|
||||
/>
|
||||
<span className={hintClasses}>
|
||||
The domain of your zitadel instance.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h5 className="text-lg mt-6 mb-2 font-semibold">Required Parameters</h5>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div className="flex flex-col">
|
||||
<label className={`${labelClasses} text-green-500`}>Client ID</label>
|
||||
<input
|
||||
className={inputClasses(false)}
|
||||
id="client_id"
|
||||
value={clientId}
|
||||
onChange={(event) => {
|
||||
const value = event.target.value;
|
||||
setClientId(value);
|
||||
}}
|
||||
/>
|
||||
<span className={hintClasses}>
|
||||
This is the resource id of an application. It's the application
|
||||
where you want your users to login.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col">
|
||||
<label className={`${labelClasses} text-blue-500`}>
|
||||
Redirect URI
|
||||
</label>
|
||||
<input
|
||||
className={inputClasses(false)}
|
||||
id="redirect_uri"
|
||||
value={redirectUri}
|
||||
onChange={(event) => {
|
||||
const value = event.target.value;
|
||||
setRedirectUri(value);
|
||||
}}
|
||||
/>
|
||||
<span className={hintClasses}>
|
||||
Must be one of the pre-configured redirect uris for your
|
||||
application.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col">
|
||||
<label className={`${labelClasses} text-orange-500`}>
|
||||
ResponseType
|
||||
</label>
|
||||
<Listbox value={responseType} onChange={setResponseType}>
|
||||
<div className="relative">
|
||||
<Listbox.Button className="transition-colors duration-300 text-black dark:text-white h-10 relative w-full cursor-default rounded-md bg-white dark:bg-input-dark-background py-2 pl-3 pr-10 text-left focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm 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">
|
||||
<span className="block truncate">{responseType}</span>
|
||||
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
||||
<ChevronUpDownIcon
|
||||
className="h-5 w-5 text-gray-400"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
</Listbox.Button>
|
||||
<span className={`${hintClasses} flex`}>
|
||||
Determines whether a code, id_token token or just id_token will
|
||||
be returned. Most use cases will need code.
|
||||
</span>
|
||||
<Transition
|
||||
as={Fragment}
|
||||
leave="transition ease-in duration-100"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<Listbox.Options className="pl-0 list-none z-10 top-10 absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white dark:bg-background-dark-300 text-black dark:text-white py-1 text-base ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
|
||||
{allResponseTypes.map((type, typeIdx) => (
|
||||
<Listbox.Option
|
||||
key={typeIdx}
|
||||
className={({ active }) =>
|
||||
`relative cursor-default select-none py-2 pl-10 pr-4 ${
|
||||
active ? "bg-black/20 dark:bg-white/20" : ""
|
||||
}`
|
||||
}
|
||||
value={type}
|
||||
>
|
||||
{({ selected }) => (
|
||||
<>
|
||||
<span
|
||||
className={`block truncate ${
|
||||
selected ? "font-medium" : "font-normal"
|
||||
}`}
|
||||
>
|
||||
{type}
|
||||
</span>
|
||||
{selected ? (
|
||||
<span className="absolute inset-y-0 left-0 flex items-center pl-3 text-orange-500 dark:text-orange-400">
|
||||
<CheckIcon
|
||||
className="h-5 w-5"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</Listbox.Option>
|
||||
))}
|
||||
</Listbox.Options>
|
||||
</Transition>
|
||||
</div>
|
||||
</Listbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 md:grid-cols-2 lg:grid-cols-3 gap-4 mt-6">
|
||||
<div className="flex flex-col">
|
||||
<label className={`${labelClasses} text-teal-600`}>
|
||||
Authentication method
|
||||
</label>
|
||||
<Listbox value={authMethod} onChange={setAuthMethod}>
|
||||
<div className="relative">
|
||||
<Listbox.Button className="transition-colors duration-300 text-black dark:text-white h-10 relative w-full cursor-default rounded-md bg-white dark:bg-input-dark-background py-2 pl-3 pr-10 text-left focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm 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">
|
||||
<span className="block truncate">{authMethod}</span>
|
||||
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
||||
<ChevronUpDownIcon
|
||||
className="h-5 w-5 text-gray-400"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
</Listbox.Button>
|
||||
<span className={`${hintClasses} flex`}>
|
||||
Authentication method
|
||||
</span>
|
||||
<Transition
|
||||
as={Fragment}
|
||||
leave="transition ease-in duration-100"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<Listbox.Options className="pl-0 list-none z-10 absolute top-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white dark:bg-background-dark-300 text-black dark:text-white py-1 text-base ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
|
||||
{allAuthMethods.map((type, typeIdx) => (
|
||||
<Listbox.Option
|
||||
key={typeIdx}
|
||||
className={({ active }) =>
|
||||
`h-10 relative cursor-default select-none py-2 pl-10 pr-4 ${
|
||||
active ? "bg-black/20 dark:bg-white/20" : ""
|
||||
}`
|
||||
}
|
||||
value={type}
|
||||
>
|
||||
{({ selected }) => (
|
||||
<>
|
||||
<span
|
||||
className={`block truncate ${
|
||||
selected ? "font-medium" : "font-normal"
|
||||
}`}
|
||||
>
|
||||
{type}
|
||||
</span>
|
||||
{selected ? (
|
||||
<span className="absolute inset-y-0 left-0 flex items-center pl-3 text-cyan-500 dark:text-cyan-400">
|
||||
<CheckIcon
|
||||
className="h-5 w-5"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</Listbox.Option>
|
||||
))}
|
||||
</Listbox.Options>
|
||||
</Transition>
|
||||
</div>
|
||||
</Listbox>
|
||||
</div>
|
||||
{authMethod === "(none) PKCE" && (
|
||||
<div className="flex flex-col">
|
||||
<label className={`${labelClasses} text-teal-600`}>
|
||||
Code Verifier
|
||||
</label>
|
||||
<input
|
||||
className={inputClasses(false)}
|
||||
id="code_verifier"
|
||||
value={codeVerifier}
|
||||
onChange={(event) => {
|
||||
const value = event.target.value;
|
||||
setCodeVerifier(value);
|
||||
}}
|
||||
/>
|
||||
<span className={hintClasses}>
|
||||
<span className="text-teal-600">Authentication method</span> PKCE
|
||||
requires a random string used to generate a{" "}
|
||||
<code>code_challenge</code>
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<h5 className="text-lg mt-6 mb-2 font-semibold">Additional Parameters</h5>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<div className="flex flex-col">
|
||||
<label className={`${labelClasses} text-cyan-500`}>Prompt</label>
|
||||
<Listbox value={prompt} onChange={setPrompt}>
|
||||
<div className="relative">
|
||||
<Listbox.Button className="transition-colors duration-300 text-black dark:text-white h-10 relative w-full cursor-default rounded-md bg-white dark:bg-input-dark-background py-2 pl-3 pr-10 text-left focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm 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">
|
||||
<span className="block truncate">{prompt}</span>
|
||||
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
||||
<ChevronUpDownIcon
|
||||
className="h-5 w-5 text-gray-400"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
</Listbox.Button>
|
||||
<span className={`${hintClasses} flex`}>
|
||||
Define how the user should be prompted on login and register.
|
||||
</span>
|
||||
<Transition
|
||||
as={Fragment}
|
||||
leave="transition ease-in duration-100"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<Listbox.Options className="pl-0 list-none z-10 absolute top-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white dark:bg-background-dark-300 text-black dark:text-white py-1 text-base ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
|
||||
{allPrompts.map((type, typeIdx) => (
|
||||
<Listbox.Option
|
||||
key={typeIdx}
|
||||
className={({ active }) =>
|
||||
`h-10 relative cursor-default select-none py-2 pl-10 pr-4 ${
|
||||
active ? "bg-black/20 dark:bg-white/20" : ""
|
||||
}`
|
||||
}
|
||||
value={type}
|
||||
>
|
||||
{({ selected }) => (
|
||||
<>
|
||||
<span
|
||||
className={`block truncate ${
|
||||
selected ? "font-medium" : "font-normal"
|
||||
}`}
|
||||
>
|
||||
{type}
|
||||
</span>
|
||||
{selected ? (
|
||||
<span className="absolute inset-y-0 left-0 flex items-center pl-3 text-cyan-500 dark:text-cyan-400">
|
||||
<CheckIcon
|
||||
className="h-5 w-5"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</Listbox.Option>
|
||||
))}
|
||||
</Listbox.Options>
|
||||
</Transition>
|
||||
</div>
|
||||
</Listbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{prompt === "select_account" && (
|
||||
<div className="flex flex-col">
|
||||
<label className={`${labelClasses} text-rose-500`}>
|
||||
Login hint
|
||||
</label>
|
||||
<input
|
||||
className={inputClasses(false)}
|
||||
id="login_hint"
|
||||
value={loginHint}
|
||||
onChange={(event) => {
|
||||
const value = event.target.value;
|
||||
setLoginHint(value);
|
||||
}}
|
||||
/>
|
||||
<span className={hintClasses}>
|
||||
This in combination with a{" "}
|
||||
<span className="text-black dark:text-white">select_account</span>{" "}
|
||||
<span className="text-cyan-500">prompt</span> the login will
|
||||
preselect a user.
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* <div className="flex flex-col">
|
||||
<label className={`${labelClasses} text-blue-500`}>
|
||||
ID Token hint
|
||||
</label>
|
||||
<input
|
||||
className={inputClasses(false)}
|
||||
id="id_token_hint"
|
||||
value={idTokenHint}
|
||||
onChange={(event) => {
|
||||
const value = event.target.value;
|
||||
setIdTokenHint(value);
|
||||
}}
|
||||
/>
|
||||
<span className={hintClasses}>
|
||||
This in combination with a{" "}
|
||||
<span className="text-black dark:text-white">select_account</span>{" "}
|
||||
<span className="text-emerald-500">prompt</span> the login will
|
||||
preselect a user.
|
||||
</span>
|
||||
</div> */}
|
||||
</div>
|
||||
|
||||
<h5 className="text-lg mt-6 mb-2 font-semibold">Scopes</h5>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-4">
|
||||
<div className="flex flex-col">
|
||||
<label className={`${labelClasses} text-purple-500`}>
|
||||
Organization ID
|
||||
</label>
|
||||
<input
|
||||
className={inputClasses(false)}
|
||||
id="organization_id"
|
||||
value={organizationId}
|
||||
onChange={(event) => {
|
||||
const value = event.target.value;
|
||||
setOrganizationId(value);
|
||||
allScopes[7] = `urn:zitadel:iam:org:id:${
|
||||
value ? value : "[organizationId]"
|
||||
}`;
|
||||
toggleScope(8, true);
|
||||
setScope(
|
||||
scopeState
|
||||
.map((checked, i) => (checked ? allScopes[i] : ""))
|
||||
.filter((s) => !!s)
|
||||
.join(" ")
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<span className={hintClasses}>
|
||||
Enforce organization policies and user membership by requesting the{" "}
|
||||
<span className="text-purple-500">scope</span>{" "}
|
||||
<code>urn:zitadel:iam:org:id:{organizationId}</code>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="py-4">
|
||||
<p className="text-sm mt-0 mb-0 text-purple-500">Scopes</p>
|
||||
<span className={`${hintClasses} flex mb-2`}>
|
||||
Request additional information about the user with scopes. The claims
|
||||
will be returned on the userinfo_endpoint or in the token (when
|
||||
configured).
|
||||
</span>
|
||||
{allScopes.map((scope, scopeIndex) => {
|
||||
return (
|
||||
<div key={`scope-${scope}`} className="flex flex-row items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={`scope_${scope}`}
|
||||
name="scopes"
|
||||
value={`${scope}`}
|
||||
checked={scopeState[scopeIndex]}
|
||||
onChange={() => {
|
||||
toggleScope(scopeIndex);
|
||||
}}
|
||||
/>
|
||||
<label className="ml-4" htmlFor={`scope_${scope}`}>
|
||||
{scope}{" "}
|
||||
{scopeIndex === 8 && scopeState[8] && !organizationId ? (
|
||||
<strong className="text-red-500">
|
||||
Organization ID missing!
|
||||
</strong>
|
||||
) : null}
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* <h5>Optional Parameters</h5>
|
||||
|
||||
<div className={styles.grid}>
|
||||
<div className={styles.inputwrapper}>
|
||||
<label className={styles.label}>Id Token Hint</label>
|
||||
<input
|
||||
className={styles.input}
|
||||
id="id_token_hint"
|
||||
value={idTokenHint}
|
||||
onChange={(event) => {
|
||||
const value = event.target.value;
|
||||
setIdTokenHint(value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
<h5 className="text-lg mt-6 mb-2 font-semibold">
|
||||
Your authorization request
|
||||
</h5>
|
||||
|
||||
<div className="rounded-md bg-gray-700 shadow dark:bg-black/10 p-2 flex flex-col items-center">
|
||||
<code className="text-sm w-full mb-4 bg-transparent border-none">
|
||||
<span className="text-yellow-500">
|
||||
{instance.endsWith("/") ? instance : instance + "/"}
|
||||
</span>
|
||||
<span className="text-white">oauth/v2/authorize?</span>
|
||||
<CodeSnipped cname="text-green-500">{`client_id=${encodeURIComponent(
|
||||
clientId
|
||||
)}`}</CodeSnipped>
|
||||
<CodeSnipped cname="text-blue-500">{`&redirect_uri=${encodeURIComponent(
|
||||
redirectUri
|
||||
)}`}</CodeSnipped>
|
||||
<CodeSnipped cname="text-orange-500">
|
||||
{`&response_type=${encodeURIComponent(responseType)}`}
|
||||
</CodeSnipped>
|
||||
<CodeSnipped cname="text-purple-500">{`&scope=${encodeURIComponent(
|
||||
scope
|
||||
)}`}</CodeSnipped>
|
||||
{prompt && (
|
||||
<CodeSnipped cname="text-cyan-500">{`&prompt=${encodeURIComponent(
|
||||
prompt
|
||||
)}`}</CodeSnipped>
|
||||
)}
|
||||
{loginHint && prompt === "select_account" && (
|
||||
<CodeSnipped cname="text-rose-500">{`&login_hint=${encodeURIComponent(
|
||||
loginHint
|
||||
)}`}</CodeSnipped>
|
||||
)}
|
||||
{authMethod === "(none) PKCE" && (
|
||||
<CodeSnipped cname="text-teal-600">{`&code_challenge=${encodeURIComponent(
|
||||
codeChallenge
|
||||
)}&code_challenge_method=S256`}</CodeSnipped>
|
||||
)}
|
||||
</code>
|
||||
|
||||
<a
|
||||
onClick={() => {
|
||||
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"
|
||||
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`
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<span>Try it out</span>
|
||||
<i className="text-white text-md ml-2 las la-external-link-alt"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,11 +1,7 @@
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
|
||||
import styles from '../css/column.module.css';
|
||||
|
||||
export default function Column({children}) {
|
||||
return (
|
||||
<div className={styles.column}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default function Column({ children }) {
|
||||
return (
|
||||
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2">{children}</div>
|
||||
);
|
||||
}
|
||||
|
133
docs/src/components/environment.jsx
Normal file
133
docs/src/components/environment.jsx
Normal file
@@ -0,0 +1,133 @@
|
||||
import React, { useContext, useEffect } from "react";
|
||||
import { EnvironmentContext } from "../utils/environment";
|
||||
import styles from "../css/environment.module.css";
|
||||
import Interpolate from "@docusaurus/Interpolate";
|
||||
import CodeBlock from "@theme/CodeBlock";
|
||||
|
||||
export function SetEnvironment() {
|
||||
const {
|
||||
instance: [instance, setInstance],
|
||||
clientId: [clientId, setClientId],
|
||||
} = useContext(EnvironmentContext);
|
||||
|
||||
useEffect(() => {
|
||||
const params = new URLSearchParams(window.location.search); // id=123
|
||||
const clientId = params.get("clientId");
|
||||
const instance = params.get("instance");
|
||||
|
||||
const localClientId = localStorage.getItem("clientId");
|
||||
const localInstance = localStorage.getItem("instance");
|
||||
|
||||
setClientId(clientId ?? localClientId ?? "");
|
||||
setInstance(instance ?? localInstance ?? "");
|
||||
}, []);
|
||||
|
||||
function setAndSaveInstance(value) {
|
||||
if (instance !== value) {
|
||||
localStorage.setItem("instance", value);
|
||||
setInstance(value);
|
||||
}
|
||||
}
|
||||
|
||||
function setAndSaveClientId(value) {
|
||||
if (clientId !== value) {
|
||||
localStorage.setItem("clientId", value);
|
||||
setClientId(value);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.inputwrapper}>
|
||||
<label className={styles.label}>Your instance domain</label>
|
||||
<input
|
||||
className={styles.input}
|
||||
id="instance"
|
||||
value={instance}
|
||||
onChange={(event) => {
|
||||
const value = event.target.value;
|
||||
if (value) {
|
||||
setAndSaveInstance(value);
|
||||
} else {
|
||||
localStorage.removeItem("instance");
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<div className={styles.inputwrapper}>
|
||||
<label className={styles.label}>Client ID</label>
|
||||
<input
|
||||
className={styles.input}
|
||||
id="clientid"
|
||||
value={clientId}
|
||||
onChange={(event) => {
|
||||
const value = event.target.value;
|
||||
if (value) {
|
||||
setAndSaveClientId(value);
|
||||
} else {
|
||||
localStorage.removeItem("clientId");
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function Env({ name }) {
|
||||
const env = useContext(EnvironmentContext);
|
||||
const variable = env[name];
|
||||
|
||||
return <div>{variable}</div>;
|
||||
}
|
||||
|
||||
export function EnvInterpolate({ children }) {
|
||||
const {
|
||||
instance: [instance],
|
||||
clientId: [clientId],
|
||||
} = useContext(EnvironmentContext);
|
||||
|
||||
return (
|
||||
<Interpolate
|
||||
values={{
|
||||
clientId,
|
||||
instance,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Interpolate>
|
||||
);
|
||||
}
|
||||
|
||||
export function EnvCode({
|
||||
language,
|
||||
title,
|
||||
code,
|
||||
showLineNumbers = false,
|
||||
children,
|
||||
}) {
|
||||
const {
|
||||
instance: [instance],
|
||||
clientId: [clientId],
|
||||
} = useContext(EnvironmentContext);
|
||||
|
||||
return (
|
||||
<CodeBlock
|
||||
language={language}
|
||||
title={title}
|
||||
showLineNumbers={showLineNumbers}
|
||||
>
|
||||
<Interpolate
|
||||
values={{
|
||||
clientId,
|
||||
instance,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Interpolate>
|
||||
</CodeBlock>
|
||||
);
|
||||
}
|
@@ -1,113 +1,181 @@
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
|
||||
import styles from '../css/list.module.css';
|
||||
import styles from "../css/list.module.css";
|
||||
|
||||
export const ICONTYPE = {
|
||||
START: <div className="rounded rounded-start">
|
||||
<i className={`las la-play-circle`}></i>
|
||||
</div>,
|
||||
TASKS: <div className="rounded rounded-start">
|
||||
<i className={`las la-tasks`}></i>
|
||||
</div>,
|
||||
ARCHITECTURE: <div className="rounded rounded-architecture">
|
||||
<i className={`las la-sitemap`}></i>
|
||||
</div>,
|
||||
INSTANCE: <div className="rounded rounded-instance">
|
||||
<i className={`las la-industry`}></i>
|
||||
</div>,
|
||||
LOGIN: <div className="rounded rounded-login">
|
||||
<i className={`las la-sign-in-alt`}></i>
|
||||
</div>,
|
||||
PRIVATELABELING: <div className="rounded rounded-privatelabel">
|
||||
<i className={`las la-swatchbook`}></i>
|
||||
</div>,
|
||||
TEXTS: <div className="rounded rounded-texts">
|
||||
<i className={`las la-paragraph`}></i>
|
||||
</div>,
|
||||
POLICY: <div className="rounded rounded-policy">
|
||||
<i className={`las la-file-contract`}></i>
|
||||
</div>,
|
||||
SERVICE: <div className="rounded rounded-service">
|
||||
<i className={`las la-concierge-bell`}></i>
|
||||
</div>,
|
||||
STORAGE: <div className="rounded rounded-storage">
|
||||
<i className={`las la-database`}></i>
|
||||
</div>,
|
||||
FOLDER: <div className="rounded rounded-storage">
|
||||
<i className={`las la-folder`}></i>
|
||||
</div>,
|
||||
FILE: <div className="rounded rounded-storage">
|
||||
<i className={`las la-file-alt`}></i>
|
||||
</div>,
|
||||
SYSTEM: <div className="rounded rounded-system">
|
||||
<i className={`las la-server`}></i>
|
||||
</div>,
|
||||
APIS: <div className="rounded rounded-apis">
|
||||
<i className={`las la-code`}></i>
|
||||
</div>,
|
||||
HELP: <div className="rounded rounded-help">
|
||||
<i className={`las la-question`}></i>
|
||||
</div>,
|
||||
HELP_REGISTER: <div className="rounded rounded-login">
|
||||
<i className={`las la-plus-circle`}></i>
|
||||
</div>,
|
||||
HELP_LOGIN: <div className="rounded rounded-login">
|
||||
<i className={`las la-sign-in-alt`}></i>
|
||||
</div>,
|
||||
HELP_PASSWORDLESS: <div className="rounded rounded-login">
|
||||
<i className={`las la-fingerprint`}></i>
|
||||
</div>,
|
||||
HELP_PASSWORD: <div className="rounded rounded-password">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" version="1.1" width="100%" height="100%" viewBox="0 0 24 24" fit="" preserveAspectRatio="xMidYMid meet" focusable="false">
|
||||
<path d="M17,7H22V17H17V19A1,1 0 0,0 18,20H20V22H17.5C16.95,22 16,21.55 16,21C16,21.55 15.05,22 14.5,22H12V20H14A1,1 0 0,0 15,19V5A1,1 0 0,0 14,4H12V2H14.5C15.05,2 16,2.45 16,3C16,2.45 16.95,2 17.5,2H20V4H18A1,1 0 0,0 17,5V7M2,7H13V9H4V15H13V17H2V7M20,15V9H17V15H20M8.5,12A1.5,1.5 0 0,0 7,10.5A1.5,1.5 0 0,0 5.5,12A1.5,1.5 0 0,0 7,13.5A1.5,1.5 0 0,0 8.5,12M13,10.89C12.39,10.33 11.44,10.38 10.88,11C10.32,11.6 10.37,12.55 11,13.11C11.55,13.63 12.43,13.63 13,13.11V10.89Z"></path>
|
||||
</svg>
|
||||
</div>,
|
||||
HELP_FACTORS: <div className="rounded rounded-login">
|
||||
<i className={`las la-fingerprint`}></i>
|
||||
</div>,
|
||||
HELP_PHONE: <div className="rounded rounded-phone">
|
||||
<i className={`las la-phone`}></i>
|
||||
</div>,
|
||||
HELP_EMAIL: <div className="rounded rounded-email">
|
||||
<i className={`las la-at`}></i>
|
||||
</div>,
|
||||
HELP_SOCIAL: <div className="rounded rounded-login">
|
||||
<i className={`las la-share-alt`}></i>
|
||||
</div>,
|
||||
START: (
|
||||
<div className="custom-rounded custom-rounded-start">
|
||||
<i className={`las la-play-circle`}></i>
|
||||
</div>
|
||||
),
|
||||
TASKS: (
|
||||
<div className="custom-rounded custom-rounded-start">
|
||||
<i className={`las la-tasks`}></i>
|
||||
</div>
|
||||
),
|
||||
ARCHITECTURE: (
|
||||
<div className="custom-rounded custom-rounded-architecture">
|
||||
<i className={`las la-sitemap`}></i>
|
||||
</div>
|
||||
),
|
||||
INSTANCE: (
|
||||
<div className="custom-rounded custom-rounded-instance">
|
||||
<i className={`las la-industry`}></i>
|
||||
</div>
|
||||
),
|
||||
LOGIN: (
|
||||
<div className="custom-rounded custom-rounded-login">
|
||||
<i className={`las la-sign-in-alt`}></i>
|
||||
</div>
|
||||
),
|
||||
PRIVATELABELING: (
|
||||
<div className="custom-rounded custom-rounded-privatelabel">
|
||||
<i className={`las la-swatchbook`}></i>
|
||||
</div>
|
||||
),
|
||||
TEXTS: (
|
||||
<div className="custom-rounded custom-rounded-texts">
|
||||
<i className={`las la-paragraph`}></i>
|
||||
</div>
|
||||
),
|
||||
POLICY: (
|
||||
<div className="custom-rounded custom-rounded-policy">
|
||||
<i className={`las la-file-contract`}></i>
|
||||
</div>
|
||||
),
|
||||
SERVICE: (
|
||||
<div className="custom-rounded custom-rounded-service">
|
||||
<i className={`las la-concierge-bell`}></i>
|
||||
</div>
|
||||
),
|
||||
STORAGE: (
|
||||
<div className="custom-rounded custom-rounded-storage">
|
||||
<i className={`las la-database`}></i>
|
||||
</div>
|
||||
),
|
||||
FOLDER: (
|
||||
<div className="custom-rounded custom-rounded-storage">
|
||||
<i className={`las la-folder`}></i>
|
||||
</div>
|
||||
),
|
||||
FILE: (
|
||||
<div className="custom-rounded custom-rounded-storage">
|
||||
<i className={`las la-file-alt`}></i>
|
||||
</div>
|
||||
),
|
||||
SYSTEM: (
|
||||
<div className="custom-rounded custom-rounded-system">
|
||||
<i className={`las la-server`}></i>
|
||||
</div>
|
||||
),
|
||||
APIS: (
|
||||
<div className="custom-rounded custom-rounded-apis">
|
||||
<i className={`las la-code`}></i>
|
||||
</div>
|
||||
),
|
||||
HELP: (
|
||||
<div className="custom-rounded custom-rounded-help">
|
||||
<i className={`las la-question`}></i>
|
||||
</div>
|
||||
),
|
||||
HELP_REGISTER: (
|
||||
<div className="custom-rounded custom-rounded-login">
|
||||
<i className={`las la-plus-circle`}></i>
|
||||
</div>
|
||||
),
|
||||
HELP_LOGIN: (
|
||||
<div className="custom-rounded custom-rounded-login">
|
||||
<i className={`las la-sign-in-alt`}></i>
|
||||
</div>
|
||||
),
|
||||
HELP_PASSWORDLESS: (
|
||||
<div className="custom-rounded custom-rounded-login">
|
||||
<i className={`las la-fingerprint`}></i>
|
||||
</div>
|
||||
),
|
||||
HELP_PASSWORD: (
|
||||
<div className="custom-rounded custom-rounded-password">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
version="1.1"
|
||||
width="100%"
|
||||
height="100%"
|
||||
viewBox="0 0 24 24"
|
||||
fit=""
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
focusable="false"
|
||||
>
|
||||
<path d="M17,7H22V17H17V19A1,1 0 0,0 18,20H20V22H17.5C16.95,22 16,21.55 16,21C16,21.55 15.05,22 14.5,22H12V20H14A1,1 0 0,0 15,19V5A1,1 0 0,0 14,4H12V2H14.5C15.05,2 16,2.45 16,3C16,2.45 16.95,2 17.5,2H20V4H18A1,1 0 0,0 17,5V7M2,7H13V9H4V15H13V17H2V7M20,15V9H17V15H20M8.5,12A1.5,1.5 0 0,0 7,10.5A1.5,1.5 0 0,0 5.5,12A1.5,1.5 0 0,0 7,13.5A1.5,1.5 0 0,0 8.5,12M13,10.89C12.39,10.33 11.44,10.38 10.88,11C10.32,11.6 10.37,12.55 11,13.11C11.55,13.63 12.43,13.63 13,13.11V10.89Z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
),
|
||||
HELP_FACTORS: (
|
||||
<div className="custom-rounded custom-rounded-login">
|
||||
<i className={`las la-fingerprint`}></i>
|
||||
</div>
|
||||
),
|
||||
HELP_PHONE: (
|
||||
<div className="custom-rounded custom-rounded-phone">
|
||||
<i className={`las la-phone`}></i>
|
||||
</div>
|
||||
),
|
||||
HELP_EMAIL: (
|
||||
<div className="custom-rounded custom-rounded-email">
|
||||
<i className={`las la-at`}></i>
|
||||
</div>
|
||||
),
|
||||
HELP_SOCIAL: (
|
||||
<div className="custom-rounded custom-rounded-login">
|
||||
<i className={`las la-share-alt`}></i>
|
||||
</div>
|
||||
),
|
||||
};
|
||||
|
||||
export function ListElement({ link, iconClasses,roundClasses, label, type, title, description}) {
|
||||
export function ListElement({
|
||||
link,
|
||||
iconClasses,
|
||||
roundClasses,
|
||||
label,
|
||||
type,
|
||||
title,
|
||||
description,
|
||||
}) {
|
||||
return (
|
||||
<a className={styles.listelement} href={link}>
|
||||
{type ? type :
|
||||
iconClasses && <div className={roundClasses}>
|
||||
{ label ? <span className={styles.listlabel}>{label}</span>: <i className={`${iconClasses}`}></i> }
|
||||
</div>
|
||||
}
|
||||
{type
|
||||
? type
|
||||
: iconClasses && (
|
||||
<div className={roundClasses}>
|
||||
{label ? (
|
||||
<span className={styles.listlabel}>{label}</span>
|
||||
) : (
|
||||
<i className={`${iconClasses}`}></i>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<h3>{title}</h3>
|
||||
<p className={styles.listelement.description}>{description}</p>
|
||||
</div>
|
||||
</a>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function ListWrapper({children, title, columns}) {
|
||||
export function ListWrapper({ children, title, columns }) {
|
||||
return (
|
||||
<div className={styles.listWrapper}>
|
||||
{title && <span className={styles.listWrapperTitle}>{title}</span>}
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function HomeListWrapper({children, image}) {
|
||||
export function HomeListWrapper({ children, image }) {
|
||||
return (
|
||||
<div className={styles.homerow}>
|
||||
{image}
|
||||
<div className={styles.homecontent}>
|
||||
{children}
|
||||
</div>
|
||||
<div className={styles.homecontent}>{children}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@@ -1,53 +1,10 @@
|
||||
.apicard {
|
||||
border-radius: 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 200px;
|
||||
background: var(--card-background);
|
||||
padding: 1rem;
|
||||
text-decoration: none;
|
||||
transition: all 0.2 ease-in-out;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.apiauth {
|
||||
background: var(--apiauthbackground);
|
||||
}
|
||||
|
||||
.apimgmt {
|
||||
background: var(--apimgmtbackground);
|
||||
}
|
||||
|
||||
.apiadmin {
|
||||
background: var(--apiadminbackground);
|
||||
}
|
||||
|
||||
.apisystem {
|
||||
background: var(--apisystembackground);
|
||||
}
|
||||
|
||||
.apiasset {
|
||||
background: var(--apiassetbackground);
|
||||
}
|
||||
|
||||
.apicard:hover {
|
||||
text-decoration: none;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
||||
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
/* .apicard h2 {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.apicard a {
|
||||
color: #bfc1cc;
|
||||
} */
|
||||
|
||||
.apicard h3,
|
||||
h4,
|
||||
h5 {
|
||||
/* color: white; */
|
||||
margin: 0.5rem 0 0 0;
|
||||
}
|
||||
|
||||
@@ -55,26 +12,3 @@ h5 {
|
||||
font-size: 14px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.fillspace {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.bottomicon {
|
||||
width: 24px;
|
||||
margin-right: 0.5rem;
|
||||
color: var(--ifm-font-color-base);
|
||||
}
|
||||
|
||||
.bottomspan {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--ifm-font-color-base);
|
||||
text-transform: uppercase;
|
||||
margin: 0;
|
||||
}
|
||||
|
@@ -1,24 +0,0 @@
|
||||
.column {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
grid-gap: 1rem;
|
||||
}
|
||||
|
||||
.item {
|
||||
border-radius: 1rem;
|
||||
transition: all 0.2s ease;
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.item:hover {
|
||||
border-radius: 1rem;
|
||||
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
@media (min-width: 1180px) {
|
||||
.column {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
}
|
@@ -1,9 +1,7 @@
|
||||
/* stylelint-disable docusaurus/copyright-header */
|
||||
/**
|
||||
* Any CSS included here will be global. The classic template
|
||||
* bundles Infima by default. Infima is a CSS framework designed to
|
||||
* work well for content-centric websites.
|
||||
*/
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@import "../../static/icons/line-awesome/css/line-awesome.min.css";
|
||||
|
||||
@font-face {
|
||||
@@ -129,6 +127,9 @@
|
||||
--footer-border: rgba(0, 0, 0, 0.12);
|
||||
--card-border: rgba(135, 149, 161, 0.2);
|
||||
--ifm-pagination-nav-color-hover: #000000;
|
||||
--input-border: #1a191954;
|
||||
--input-hover-border: #000000;
|
||||
--input-background: #00000004;
|
||||
}
|
||||
|
||||
pre code {
|
||||
@@ -303,6 +304,9 @@ h2 {
|
||||
--footer-border: rgba(255, 255, 255, 0.12);
|
||||
--card-border: rgba(135, 149, 161, 0.2);
|
||||
--ifm-pagination-nav-color-hover: #ffffff;
|
||||
--input-border: #f9f7f775;
|
||||
--input-hover-border: #ffffff;
|
||||
--input-background: #00000040;
|
||||
}
|
||||
|
||||
.get-started:hover {
|
||||
@@ -325,7 +329,7 @@ main .container img {
|
||||
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.rounded {
|
||||
.custom-rounded {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -336,51 +340,51 @@ main .container img {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.rounded svg {
|
||||
.custom-rounded svg {
|
||||
fill: white;
|
||||
height: 1.5rem;
|
||||
width: 1.5rem;
|
||||
}
|
||||
|
||||
.rounded i {
|
||||
.custom-rounded i {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.rounded-start {
|
||||
.custom-rounded-start {
|
||||
background: linear-gradient(40deg, #059669 30%, #047857);
|
||||
}
|
||||
|
||||
.rounded-password {
|
||||
.custom-rounded-password {
|
||||
background: linear-gradient(40deg, #f59e0b 30%, #b45309);
|
||||
}
|
||||
|
||||
.rounded-login,
|
||||
.rounded-register {
|
||||
.custom-rounded-login,
|
||||
.custom-rounded-register {
|
||||
background: linear-gradient(40deg, #059669 30%, #047857);
|
||||
}
|
||||
|
||||
.rounded-privatelabel,
|
||||
.rounded-phone,
|
||||
.rounded-email,
|
||||
.rounded-storage,
|
||||
.rounded-service {
|
||||
.custom-rounded-privatelabel,
|
||||
.custom-rounded-phone,
|
||||
.custom-rounded-email,
|
||||
.custom-rounded-storage,
|
||||
.custom-rounded-service {
|
||||
background: linear-gradient(40deg, #3b82f6 30%, #4f46e5);
|
||||
}
|
||||
|
||||
.rounded-split {
|
||||
.custom-rounded-split {
|
||||
background: linear-gradient(40deg, #3b82f6, #4f46e5);
|
||||
}
|
||||
|
||||
.rounded-texts,
|
||||
.rounded-help,
|
||||
.rounded-architecture {
|
||||
.custom-rounded-texts,
|
||||
.custom-rounded-help,
|
||||
.custom-rounded-architecture {
|
||||
background: linear-gradient(40deg, #dc2626 30%, #db2777);
|
||||
}
|
||||
|
||||
.rounded-system,
|
||||
.rounded-apis,
|
||||
.rounded-policy,
|
||||
.rounded-instance {
|
||||
.custom-rounded-system,
|
||||
.custom-rounded-apis,
|
||||
.custom-rounded-policy,
|
||||
.custom-rounded-instance {
|
||||
background: linear-gradient(40deg, #1f2937, #111827);
|
||||
}
|
||||
|
||||
@@ -483,7 +487,7 @@ table th {
|
||||
}
|
||||
|
||||
a {
|
||||
transition: all 1s ease;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.alert {
|
||||
|
42
docs/src/css/environment.module.css
Normal file
42
docs/src/css/environment.module.css
Normal file
@@ -0,0 +1,42 @@
|
||||
.inputwrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 14px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.input {
|
||||
box-sizing: border-box;
|
||||
padding-inline-start: 10px;
|
||||
outline: none;
|
||||
display: inline-block;
|
||||
text-align: start;
|
||||
cursor: text;
|
||||
transform: all 0.2 linear;
|
||||
font-size: 1rem;
|
||||
border: none;
|
||||
border: 1px solid var(--input-border);
|
||||
background-color: var(--input-background);
|
||||
border-radius: 4px;
|
||||
height: 40px;
|
||||
padding: 10px;
|
||||
max-width: 400px;
|
||||
transition: border-color 0.15s ease-in-out,
|
||||
background-color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1),
|
||||
color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
width: 100%;
|
||||
color: var(--ifm-font-color-base);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
input:hover {
|
||||
border-color: var(--input-hover-border);
|
||||
}
|
||||
|
||||
input:active,
|
||||
input:focus {
|
||||
border-color: var(--ifm-color-primary);
|
||||
}
|
@@ -60,7 +60,7 @@ const features = [
|
||||
<ListElement
|
||||
link="docs/guides/solution-scenarios/introduction"
|
||||
iconClasses="las la-paragraph"
|
||||
roundClasses="rounded rounded-split"
|
||||
roundClasses="custom-rounded custom-rounded-split"
|
||||
label="B2C"
|
||||
title="Solution Scenarios"
|
||||
description=""
|
||||
@@ -255,14 +255,12 @@ function Feature({
|
||||
|
||||
const Gigi = () => {
|
||||
return (
|
||||
|
||||
<div className={styles.gigiwrapper}>
|
||||
<div className={styles.gigiwrapperrelative}>
|
||||
<img height="151px" width="256px" src="/img/gigi.svg" />
|
||||
<div className={styles.gigibanner}>ZITADEL Cloud OUT NOW! 🚀</div>
|
||||
</div>
|
||||
<div className={styles.gigiwrapper}>
|
||||
<div className={styles.gigiwrapperrelative}>
|
||||
<img height="151px" width="256px" src="/img/gigi.svg" />
|
||||
<div className={styles.gigibanner}>ZITADEL Cloud OUT NOW! 🚀</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -270,9 +268,7 @@ export default function Home() {
|
||||
const context = useDocusaurusContext();
|
||||
const { siteConfig = {} } = context;
|
||||
return (
|
||||
<Layout
|
||||
description={`${siteConfig.customFields.description}`}
|
||||
>
|
||||
<Layout description={`${siteConfig.customFields.description}`}>
|
||||
<header className={clsx("hero", styles.heroBanner)}>
|
||||
<div className="container">
|
||||
<h1 className="hero__title">{siteConfig.title}</h1>
|
||||
|
10
docs/src/theme/Footer/index.js
Normal file
10
docs/src/theme/Footer/index.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import React from "react";
|
||||
import Footer from "@theme-original/Footer";
|
||||
|
||||
export default function FooterWrapper(props) {
|
||||
return (
|
||||
<>
|
||||
<Footer {...props} />
|
||||
</>
|
||||
);
|
||||
}
|
12
docs/src/theme/Root/index.js
Normal file
12
docs/src/theme/Root/index.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import React from "react";
|
||||
import AuthRequestProvider from "../../utils/authrequest";
|
||||
// import EnvironmentProvider from "../../utils/environment";
|
||||
|
||||
// Default implementation, that you can customize
|
||||
export default function Root({ children }) {
|
||||
return (
|
||||
// <EnvironmentProvider>
|
||||
<AuthRequestProvider>{children}</AuthRequestProvider>
|
||||
// </EnvironmentProvider>
|
||||
);
|
||||
}
|
90
docs/src/utils/authrequest.js
Normal file
90
docs/src/utils/authrequest.js
Normal file
@@ -0,0 +1,90 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
export const AuthRequestContext = React.createContext(null);
|
||||
|
||||
export default ({ children }) => {
|
||||
const [instance, setInstance] = useState("your-instance");
|
||||
const [clientId, setClientId] = useState("your-client-id");
|
||||
const [redirectUri, setRedirectUri] = useState("your-redirect-uri");
|
||||
const [responseType, setResponseType] = useState("your-response-type");
|
||||
const [scope, setScope] = useState("your-scope");
|
||||
|
||||
const [prompt, setPrompt] = useState("your-prompt");
|
||||
const [authMethod, setAuthMethod] = useState("your-auth-method");
|
||||
const [codeChallenge, setCodeChallenge] = useState("your-code-challenge");
|
||||
const [codeVerifier, setCodeVerifier] = useState("your-code-verifier");
|
||||
const [loginHint, setLoginHint] = useState("your-login-hint");
|
||||
const [idTokenHint, setIdTokenHint] = useState("your-id-token-hint");
|
||||
const [organizationId, setOrganizationId] = useState("your-organization-id");
|
||||
|
||||
useEffect(() => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
|
||||
const instance_param = params.get("instance");
|
||||
const client_id = params.get("client_id");
|
||||
const redirect_uri = params.get("redirect_uri");
|
||||
const response_type = params.get("response_type");
|
||||
const scope_param = params.get("scope");
|
||||
|
||||
// optional parameters
|
||||
const prompt_param = params.get("prompt");
|
||||
const auth_method_param = params.get("auth_method");
|
||||
const code_verifier_param = params.get("code_verifier");
|
||||
const login_hint = params.get("login_hint");
|
||||
const id_token_hint = params.get("id_token_hint");
|
||||
const organization_id = params.get("organization_id");
|
||||
|
||||
setInstance(instance_param ?? "https://mydomain-xyza.zitadel.cloud/");
|
||||
setClientId(client_id ?? "170086824411201793@yourapp");
|
||||
setRedirectUri(
|
||||
redirect_uri ?? "http://localhost:8080/api/auth/callback/zitadel"
|
||||
);
|
||||
setResponseType(response_type ?? "code");
|
||||
setScope(scope_param ?? "openid email profile");
|
||||
setPrompt(prompt_param ?? "");
|
||||
setAuthMethod(auth_method_param ?? "(none) PKCE");
|
||||
setCodeVerifier(code_verifier_param ?? "random-string");
|
||||
// optional parameters
|
||||
setLoginHint(login_hint ?? "johndoe@example.zitadel.cloud");
|
||||
setIdTokenHint(id_token_hint ?? "[your-id-token]");
|
||||
setOrganizationId(organization_id ?? "168811945419506433");
|
||||
|
||||
if (
|
||||
instance_param ||
|
||||
client_id ||
|
||||
redirect_uri ||
|
||||
response_type ||
|
||||
scope_param ||
|
||||
prompt_param ||
|
||||
organization_id ||
|
||||
login_hint ||
|
||||
id_token_hint
|
||||
) {
|
||||
const example = document.getElementById("example");
|
||||
if (example) {
|
||||
example.scrollIntoView();
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
const authRequest = {
|
||||
instance: [instance, setInstance],
|
||||
clientId: [clientId, setClientId],
|
||||
redirectUri: [redirectUri, setRedirectUri],
|
||||
responseType: [responseType, setResponseType],
|
||||
scope: [scope, setScope],
|
||||
prompt: [prompt, setPrompt],
|
||||
authMethod: [authMethod, setAuthMethod],
|
||||
codeChallenge: [codeChallenge, setCodeChallenge],
|
||||
codeVerifier: [codeVerifier, setCodeVerifier],
|
||||
loginHint: [loginHint, setLoginHint],
|
||||
idTokenHint: [idTokenHint, setIdTokenHint],
|
||||
organizationId: [organizationId, setOrganizationId],
|
||||
};
|
||||
|
||||
return (
|
||||
<AuthRequestContext.Provider value={authRequest}>
|
||||
{children}
|
||||
</AuthRequestContext.Provider>
|
||||
);
|
||||
};
|
31
docs/src/utils/environment.js
Normal file
31
docs/src/utils/environment.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
export const EnvironmentContext = React.createContext(null);
|
||||
|
||||
export default ({ children }) => {
|
||||
const [instance, setInstance] = useState("your-instance");
|
||||
const [clientId, setClientId] = useState("your-client-id");
|
||||
|
||||
useEffect(() => {
|
||||
const params = new URLSearchParams(window.location.search); // id=123
|
||||
const clientId = params.get("clientId");
|
||||
const instance = params.get("instance");
|
||||
|
||||
const localClientId = localStorage.getItem("clientId");
|
||||
const localInstance = localStorage.getItem("instance");
|
||||
|
||||
setClientId(clientId ?? localClientId ?? "");
|
||||
setInstance(instance ?? localInstance ?? "");
|
||||
}, []);
|
||||
|
||||
const environment = {
|
||||
instance: [instance, setInstance],
|
||||
clientId: [clientId, setClientId],
|
||||
};
|
||||
|
||||
return (
|
||||
<EnvironmentContext.Provider value={environment}>
|
||||
{children}
|
||||
</EnvironmentContext.Provider>
|
||||
);
|
||||
};
|
Reference in New Issue
Block a user