> ## Documentation Index
> Fetch the complete documentation index at: https://translations.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Esta guía muestra cómo integrar Auth0, añadir autenticación y mostrar la información del perfil del usuario en cualquier aplicación PHP mediante el SDK de Auth0 para PHP.

# Añade el inicio de sesión a tu aplicación PHP

export const AuthCodeGroup = ({children, dropdown}) => {
  const [processedChildren, setProcessedChildren] = useState(children);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      unsubscribe = window.autorun(() => {
        const processChildren = node => {
          if (typeof node === "string") {
            let processedNode = node;
            for (const [key, value] of window.rootStore.variableStore.values.entries()) {
              const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
              processedNode = processedNode.replaceAll(new RegExp(escapedKey, "g"), value);
            }
            return processedNode;
          } else if (Array.isArray(node)) {
            return node.map(processChildren);
          } else if (node && node.props && node.props.children) {
            return {
              ...node,
              props: {
                ...node.props,
                children: processChildren(node.props.children)
              }
            };
          }
          return node;
        };
        setProcessedChildren(processChildren(children));
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  return <CodeGroup dropdown={dropdown}>{processedChildren}</CodeGroup>;
};

export const QuickstartButtons = ({githubLink}) => {
  const text = {
    viewOnGithub: "Ver en GitHub",
    loginAndDownload: "Descargar ejemplo"
  };
  const parseGithubUrl = url => {
    try {
      const urlObj = new URL(url);
      const pathParts = urlObj.pathname.split("/").filter(Boolean);
      if (pathParts.length >= 4 && pathParts[2] === "tree") {
        const repoName = pathParts[1];
        const branch = pathParts[3];
        const path = pathParts.slice(4).join("/") || undefined;
        return {
          repo: repoName,
          branch,
          path
        };
      }
      console.warn("No se pudo analizar la URL de GitHub:", url);
      return null;
    } catch (error) {
      console.error("Error al analizar la URL de GitHub:", error);
      return null;
    }
  };
  const handleDownload = async () => {
    const params = parseGithubUrl(githubLink);
    if (!params) {
      console.error("Formato de URL de GitHub no válido");
      return;
    }
    try {
      await window.Auth0DocsUI?.getSample(params);
    } catch (error) {
      console.error("No se pudo descargar el ejemplo:", error);
    }
  };
  return <div className="quickstart_buttons flex flex-wrap gap-3 mb-4">
      <a href={githubLink} target="_blank" rel="noopener noreferrer" className="no_external_icon quickstart_button inline-flex items-center justify-center px-6 py-3 text-sm font-medium rounded-[18px] bg-black dark:bg-white !text-white dark:!text-black hover:bg-gray-800 dark:hover:bg-gray-100 transition-colors">
        {text.viewOnGithub}
      </a>
      <button onClick={handleDownload} type="button" className="no_external_icon quickstart_button inline-flex items-center justify-center px-6 py-3 text-sm font-medium rounded-[18px] border border-gray-300 dark:border-[#454545] bg-white dark:bg-[#272728] !text-black dark:!text-white hover:bg-gray-50 dark:hover:bg-neutral-800 transition-colors">
        {text.loginAndDownload}
      </button>
    </div>;
};

export const LoggedInForm = ({sampleApp}) => {
  const LS_APPS_KEY = "auth_demo_apps";
  const LS_APP_CFG_KEY = "auth_demo_app_cfg";
  const CHANNEL = "auth_flows_sync_v1";
  const mkChannel = () => new BroadcastChannel(CHANNEL);
  function uid() {
    return Math.random().toString(36).slice(2) + Date.now().toString(36);
  }
  function loadApps() {
    const raw = localStorage.getItem(LS_APPS_KEY);
    if (raw) return JSON.parse(raw);
    const seeded = [{
      id: "{yourClientId}",
      name: "Default App"
    }];
    localStorage.setItem(LS_APPS_KEY, JSON.stringify(seeded));
    return seeded;
  }
  function saveApps(apps) {
    localStorage.setItem(LS_APPS_KEY, JSON.stringify(apps));
  }
  function loadCfg() {
    const raw = localStorage.getItem(LS_APP_CFG_KEY);
    return raw ? JSON.parse(raw) : {};
  }
  function saveCfg(cfg) {
    localStorage.setItem(LS_APP_CFG_KEY, JSON.stringify(cfg));
  }
  const RightChevron = ({className = "w-5 h-5", ...props}) => <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="currentColor" fill="none" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className} {...props}>
      <polyline points="9 18 15 12 9 6" />
    </svg>;
  const LightningIcon = () => <svg width="24" height="24" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
      <path fillRule="evenodd" clipRule="evenodd" className="fill-[#3F59E4] dark:fill-[#99A7F1]" d="M24.971 30.152H7.088c-1.786 0-2.745-2.103-1.574-3.453l19.07-21.988c1.33-1.532 3.835-.4 3.569 1.607L24.97 30.152z" />
      <path fillRule="evenodd" clipRule="evenodd" className="fill-[#3F59E4] dark:fill-[#99A7F1]" d="M23.201 17.885h17.885c1.787 0 2.746 2.102 1.575 3.453l-19.073 21.99c-1.33 1.532-3.835.4-3.568-1.607L23.2 17.885z" />
    </svg>;
  const LayersIcon = () => <svg width="24" height="24" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
      <path className="fill-[#3F59E4] dark:fill-[#99A7F1]" d="M34.54 29.135l6.373 3.183c1.566.782 1.566 3.017 0 3.8l-14.815 7.396a4.623 4.623 0 01-4.125 0L7.174 36.12c-1.565-.782-1.565-3.017 0-3.798l6.532-3.214" />
      <path className="fill-[#AAB6F3] dark:fill-[#3449BA]" d="M34.54 18.86l6.373 3.183c1.566.782 1.566 3.016 0 3.8L26.098 33.24a4.623 4.623 0 01-4.125 0L7.174 25.843c-1.565-.781-1.565-3.016 0-3.798l6.33-3.164" />
      <path className="fill-[#CFD6F8] dark:fill-[#22307C]" d="M21.94 23.058L7.306 15.745c-1.62-.81-1.62-3.123 0-3.932l14.631-7.319a4.693 4.693 0 014.194 0l14.648 7.319c1.622.81 1.62 3.124 0 3.932L26.13 23.058c-1.321.66-2.873.66-4.191 0z" />
    </svg>;
  const GithubIcon = () => <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="w-5 h-5">
      <path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
    </svg>;
  function IconTile({children}) {
    return <div className="
          shrink-0 grid place-items-center w-10 h-10 rounded-lg
          bg-indigo-50 ring-1 ring-indigo-200/60
          dark:bg-indigo-950/40 dark:ring-white/10
        ">
        {children}
      </div>;
  }
  function Card({className = "", children}) {
    return <div className={`rounded-2xl shadow-sm ring-1 ring-zinc-200 dark:ring-zinc-800 ${className}`}>{children}</div>;
  }
  function Button({variant = "primary", type = "button", onClick, children}) {
    const base = "inline-flex items-center justify-center gap-2 h-10 px-4 rounded-xl font-medium transition";
    let styles = "";
    if (variant === "primary") {
      styles = "mint-bg-indigo-600 text-white hover:mint-bg-indigo-700";
    } else if (variant === "outline") {
      styles = "border border-zinc-300 dark:border-zinc-700 mint-bg-transparent hover:mint-bg-zinc-50 dark:hover:mint-bg-zinc-800";
    } else if (variant === "ghost") {
      styles = "hover:mint-bg-zinc-100 dark:hover:mint-bg-zinc-800";
    }
    return <button type={type} onClick={onClick} className={`${base} ${styles}`}>
        {children}
      </button>;
  }
  function Input({id, label, value, onChange, placeholder, name}) {
    return <label className="block space-y-1">
        <span className="text-sm text-zinc-700 dark:text-zinc-300">{label}</span>
        <input id={id} name={name} className="w-full h-11 px-3 rounded-xl border border-zinc-300 dark:border-zinc-700 bg-white dark:bg-zinc-900 text-zinc-900 dark:text-zinc-100 focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder={placeholder} value={value} onChange={e => onChange(e.target.value)} />
      </label>;
  }
  function Select({label, value, onChange, options}) {
    return <label className="block space-y-1 max-w-[300px]">
        <span className="text-sm text-zinc-700 dark:text-zinc-300">{label}</span>
        <div className="relative">
          <select className="w-full h-11 appearance-none px-3 pr-9 rounded-xl border border-zinc-300 dark:border-zinc-700 bg-white dark:bg-zinc-900 text-zinc-900 dark:text-zinc-100 focus:outline-none focus:ring-2 focus:ring-indigo-500" value={value} onChange={e => onChange(e.target.value)}>
            <optgroup label="Generic Applications">
              {options.map(o => <option key={o.id} value={o.id}>
                  {o.name}
                </option>)}
            </optgroup>
          </select>
          <svg className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 w-5 h-5 text-zinc-500" viewBox="0 0 24 24">
            <path d="M7 10l5 5 5-5z" fill="currentColor" />
          </svg>
        </div>
      </label>;
  }
  function Toast({open, onClose, children}) {
    useEffect(() => {
      if (!open) return;
      const t = setTimeout(onClose, 2200);
      return () => clearTimeout(t);
    }, [open, onClose]);
    return <div className={`fixed right-4 top-4 z-50 transition ${open ? "opacity-100 translate-y-0" : "opacity-0 -translate-y-2 pointer-events-none"}`}>
        <div className="flex items-center gap-2 rounded-xl shadow ring-1 ring-emerald-200 bg-white dark:bg-zinc-900 px-4 py-2">
          <span className="w-1.5 h-8 rounded-l bg-emerald-500" />
          <svg className="w-5 h-5 text-emerald-600" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
            <path d="M20 6L9 17l-5-5" />
          </svg>
          <span className="text-sm text-zinc-900 dark:text-zinc-100">{children}</span>
        </div>
      </div>;
  }
  function Flows() {
    const [route, setRoute] = useState("menu");
    const [apps, setApps] = useState(loadApps());
    const [cfg, setCfg] = useState(loadCfg());
    const [selected, setSelected] = useState(apps[0]?.id || "");
    const [toast, setToast] = useState(false);
    const [bc] = useState(() => mkChannel());
    useEffect(() => {
      if (!apps.find(a => a.id === selected)) {
        setSelected(apps[0]?.id || "");
      }
    }, [apps, selected]);
    useEffect(() => {
      const onMsg = e => {
        const {type, payload} = e.data || ({});
        switch (type) {
          case "NAV":
            setRoute(payload.route);
            break;
          case "SELECT":
            setSelected(payload.appId);
            break;
          case "APPS_UPDATED":
            setApps(loadApps());
            break;
          case "CFG_UPDATED":
            setCfg(loadCfg());
            setToast(true);
            break;
          default:
            break;
        }
      };
      bc.addEventListener("message", onMsg);
      return () => bc.removeEventListener("message", onMsg);
    }, [bc]);
    const nav = nextRoute => {
      setRoute(nextRoute);
      bc.postMessage({
        type: "NAV",
        payload: {
          route: nextRoute
        }
      });
    };
    const selectApp = appId => {
      setSelected(appId);
      bc.postMessage({
        type: "SELECT",
        payload: {
          appId
        }
      });
    };
    const onCreate = name => {
      const id = uid();
      const next = [...apps, {
        id,
        name: name || "Untitled"
      }];
      setApps(next);
      saveApps(next);
      bc.postMessage({
        type: "APPS_UPDATED"
      });
      selectApp(id);
      nav("integrate");
    };
    const onSaveCfg = (appId, data) => {
      const next = {
        ...cfg,
        [appId]: data
      };
      setCfg(next);
      saveCfg(next);
      setToast(true);
      bc.postMessage({
        type: "CFG_UPDATED"
      });
    };
    return <div>
        {route === "menu" && <Menu onCreate={() => nav("create")} onIntegrate={() => nav("integrate")} />}

        {route === "create" && <CreateForm onCancel={() => nav("menu")} onSave={onCreate} />}

        {route === "integrate" && <IntegrateForm apps={apps} selected={selected} onSelect={selectApp} saved={cfg[selected]} onSave={data => onSaveCfg(selected, data)} onCancel={() => nav("menu")} />}

        <Toast open={toast} onClose={() => setToast(false)}>
          Successfully saved your changes.
        </Toast>
      </div>;
  }
  function Menu({onCreate, onIntegrate}) {
    return <ul className="space-y-4 list-none login_list">
        <li className="list-none !px-0">
          <button onClick={onCreate} className="w-full text-left">
            <Card className="p-5 hover:shadow-md transition">
              <div className="flex items-center justify-between">
                <div className="flex items-center gap-4">
                  <IconTile>
                    <LightningIcon />
                  </IconTile>
                  <h2 className="text-lg">Create a new application</h2>
                </div>
                <RightChevron className="w-4 h-4 text-zinc-500" />
              </div>
            </Card>
          </button>
        </li>
        <li className="list-none !px-0">
          <button onClick={onIntegrate} className="w-full text-left">
            <Card className="p-5 hover:shadow-md transition">
              <div className="flex items-center justify-between">
                <div className="flex items-center gap-4">
                  <IconTile>
                    <LayersIcon />
                  </IconTile>
                  <h2 className="text-lg">Integrate with an existing application</h2>
                </div>
                <RightChevron className="w-4 h-4 text-zinc-500" />
              </div>
            </Card>
          </button>
        </li>
        <li className="list-none !px-0">
          <a className="no_external_icon block" href={sampleApp ? sampleApp : "/"} target="_blank" rel="noreferrer">
            <Card className="p-5 hover:shadow-md transition">
              <div className="flex items-center justify-between">
                <div className="flex items-center gap-4">
                  <IconTile>
                    <GithubIcon />
                  </IconTile>
                  <h2 className="text-lg">View a sample application</h2>
                </div>
                <RightChevron className="w-4 h-4 text-zinc-500" />
              </div>
            </Card>
          </a>
        </li>
      </ul>;
  }
  function CreateForm({onSave, onCancel}) {
    const [name, setName] = useState("");
    return <div className="space-y-6">
        <Input id="app-name" label="Application Name" placeholder="My App" value={name} onChange={setName} />
        <p className="text-sm text-zinc-500">You can change this later in the application settings.</p>
        <div className="flex gap-3">
          <Button onClick={() => onSave(name)}>Guardar</Button>
          <Button variant="outline" onClick={onCancel}>
            Cancelar
          </Button>
        </div>
      </div>;
  }
  function IntegrateForm({apps, selected, onSelect, saved, onSave, onCancel}) {
    const [callbacks, setCallbacks] = useState(saved?.callbacks ?? "");
    const [logouts, setLogouts] = useState(saved?.logouts ?? "");
    const [origins, setOrigins] = useState(saved?.origins ?? "");
    useEffect(() => {
      setCallbacks(loadCfg()[selected]?.callbacks ?? "");
      setLogouts(loadCfg()[selected]?.logouts ?? "");
      setOrigins(loadCfg()[selected]?.origins ?? "");
    }, [selected]);
    return <div className="space-y-6">
        <div>
          <span className="block text-sm text-zinc-600 dark:text-zinc-300 mb-1">Selecciona tu aplicación</span>
          <Select label="" value={selected} onChange={onSelect} options={apps} />
        </div>

        <form className="space-y-4" onSubmit={e => {
      e.preventDefault();
      onSave({
        callbacks,
        logouts,
        origins
      });
    }}>
          <Input id="callbacks" name="callbacks" label="URLs de callback" placeholder="http://localhost:3000" value={callbacks} onChange={setCallbacks} />
          <Input id="logout" name="allowed_logout_urls" label="URLs de cierre de sesión" placeholder="http://localhost:3000" value={logouts} onChange={setLogouts} />
          <Input id="origins" name="web_origins" label="Orígenes web permitidos" placeholder="http://localhost:3000" value={origins} onChange={setOrigins} />

          <div className="flex gap-3 pt-2">
            <Button type="submit">Guardar</Button>
            <Button variant="outline" type="button" onClick={onCancel}>
              Cancelar
            </Button>
          </div>
        </form>
      </div>;
  }
  return <div className="w-full mx-auto py-8">
      <Flows />
    </div>;
};

export const SignUpForm = () => {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [storeReady, setStoreReady] = useState(false);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      setStoreReady(true);
      unsubscribe = window.autorun(() => {
        const authenticated = window.rootStore?.sessionStore?.isAuthenticated || false;
        setIsAuthenticated(authenticated);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, []);
  function LoggedInForm({sampleApp}) {
    const LS_APPS_KEY = "auth_demo_apps";
    const LS_APP_CFG_KEY = "auth_demo_app_cfg";
    const CHANNEL = "auth_flows_sync_v1";
    const mkChannel = () => new BroadcastChannel(CHANNEL);
    function uid() {
      return Math.random().toString(36).slice(2) + Date.now().toString(36);
    }
    function loadApps() {
      const raw = localStorage.getItem(LS_APPS_KEY);
      if (raw) return JSON.parse(raw);
      const seeded = [{
        id: "{yourClientId}",
        name: "Aplicación predeterminada"
      }];
      localStorage.setItem(LS_APPS_KEY, JSON.stringify(seeded));
      return seeded;
    }
    function saveApps(apps) {
      localStorage.setItem(LS_APPS_KEY, JSON.stringify(apps));
    }
    function loadCfg() {
      const raw = localStorage.getItem(LS_APP_CFG_KEY);
      return raw ? JSON.parse(raw) : {};
    }
    function saveCfg(cfg) {
      localStorage.setItem(LS_APP_CFG_KEY, JSON.stringify(cfg));
    }
    const RightChevron = ({className = "w-5 h-5", ...props}) => <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="currentColor" fill="none" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className} {...props}>
        <polyline points="9 18 15 12 9 6" />
      </svg>;
    const LightningIcon = () => <svg width="24" height="24" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fillRule="evenodd" clipRule="evenodd" className="fill-[#3F59E4] dark:fill-[#99A7F1]" d="M24.971 30.152H7.088c-1.786 0-2.745-2.103-1.574-3.453l19.07-21.988c1.33-1.532 3.835-.4 3.569 1.607L24.97 30.152z" />
        <path fillRule="evenodd" clipRule="evenodd" className="fill-[#3F59E4] dark:fill-[#99A7F1]" d="M23.201 17.885h17.885c1.787 0 2.746 2.102 1.575 3.453l-19.073 21.99c-1.33 1.532-3.835.4-3.568-1.607L23.2 17.885z" />
      </svg>;
    const LayersIcon = () => <svg width="24" height="24" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path className="fill-[#3F59E4] dark:fill-[#99A7F1]" d="M34.54 29.135l6.373 3.183c1.566.782 1.566 3.017 0 3.8l-14.815 7.396a4.623 4.623 0 01-4.125 0L7.174 36.12c-1.565-.782-1.565-3.017 0-3.798l6.532-3.214" />
        <path className="fill-[#AAB6F3] dark:fill-[#3449BA]" d="M34.54 18.86l6.373 3.183c1.566.782 1.566 3.016 0 3.8L26.098 33.24a4.623 4.623 0 01-4.125 0L7.174 25.843c-1.565-.781-1.565-3.016 0-3.798l6.33-3.164" />
        <path className="fill-[#CFD6F8] dark:fill-[#22307C]" d="M21.94 23.058L7.306 15.745c-1.62-.81-1.62-3.123 0-3.932l14.631-7.319a4.693 4.693 0 014.194 0l14.648 7.319c1.622.81 1.62 3.124 0 3.932L26.13 23.058c-1.321.66-2.873.66-4.191 0z" />
      </svg>;
    const GithubIcon = () => <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="w-5 h-5">
        <path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
      </svg>;
    function IconTile({children}) {
      return <div className="
            shrink-0 grid place-items-center w-10 h-10 rounded-lg
            bg-indigo-50 ring-1 ring-indigo-200/60
            dark:bg-indigo-950/40 dark:ring-white/10
          ">
          {children}
        </div>;
    }
    function Card({className = "", children}) {
      return <div className={`rounded-2xl shadow-sm ring-1 ring-zinc-200 dark:ring-zinc-800 ${className}`}>{children}</div>;
    }
    function Button({variant = "primary", type = "button", onClick, children}) {
      const base = "inline-flex items-center justify-center gap-2 h-10 px-4 rounded-xl font-medium transition";
      let styles = "";
      if (variant === "primary") {
        styles = "mint-bg-indigo-600 text-white hover:mint-bg-indigo-700";
      } else if (variant === "outline") {
        styles = "border border-zinc-300 dark:border-zinc-700 mint-bg-transparent hover:mint-bg-zinc-50 dark:hover:mint-bg-zinc-800";
      } else if (variant === "ghost") {
        styles = "hover:mint-bg-zinc-100 dark:hover:mint-bg-zinc-800";
      }
      return <button type={type} onClick={onClick} className={`${base} ${styles}`}>
          {children}
        </button>;
    }
    function Input({id, label, value, onChange, placeholder, name}) {
      return <label className="block space-y-1">
          <span className="text-sm text-zinc-700 dark:text-zinc-300">{label}</span>
          <input id={id} name={name} className="w-full h-11 px-3 rounded-xl border border-zinc-300 dark:border-zinc-700 bg-white dark:bg-zinc-900 text-zinc-900 dark:text-zinc-100 focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder={placeholder} value={value} onChange={e => onChange(e.target.value)} />
        </label>;
    }
    function Select({label, value, onChange, options}) {
      return <label className="block space-y-1 max-w-[300px]">
          <span className="text-sm text-zinc-700 dark:text-zinc-300">{label}</span>
          <div className="relative">
            <select className="w-full h-11 appearance-none px-3 pr-9 rounded-xl border border-zinc-300 dark:border-zinc-700 bg-white dark:bg-zinc-900 text-zinc-900 dark:text-zinc-100 focus:outline-none focus:ring-2 focus:ring-indigo-500" value={value} onChange={e => onChange(e.target.value)}>
              <optgroup label="Generic Applications">
                {options.map(o => <option key={o.id} value={o.id}>
                    {o.name}
                  </option>)}
              </optgroup>
            </select>
            <svg className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 w-5 h-5 text-zinc-500" viewBox="0 0 24 24">
              <path d="M7 10l5 5 5-5z" fill="currentColor" />
            </svg>
          </div>
        </label>;
    }
    function Toast({open, onClose, children}) {
      useEffect(() => {
        if (!open) return;
        const t = setTimeout(onClose, 2200);
        return () => clearTimeout(t);
      }, [open, onClose]);
      return <div className={`fixed right-4 top-4 z-50 transition ${open ? "opacity-100 translate-y-0" : "opacity-0 -translate-y-2 pointer-events-none"}`}>
          <div className="flex items-center gap-2 rounded-xl shadow ring-1 ring-emerald-200 bg-white dark:bg-zinc-900 px-4 py-2">
            <span className="w-1.5 h-8 rounded-l bg-emerald-500" />
            <svg className="w-5 h-5 text-emerald-600" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
              <path d="M20 6L9 17l-5-5" />
            </svg>
            <span className="text-sm text-zinc-900 dark:text-zinc-100">{children}</span>
          </div>
        </div>;
    }
    function Flows() {
      const [route, setRoute] = useState("menu");
      const [apps, setApps] = useState(loadApps());
      const [cfg, setCfg] = useState(loadCfg());
      const [selected, setSelected] = useState(apps[0]?.id || "");
      const [toast, setToast] = useState(false);
      const [bc] = useState(() => mkChannel());
      useEffect(() => {
        if (!apps.find(a => a.id === selected)) {
          setSelected(apps[0]?.id || "");
        }
      }, [apps, selected]);
      useEffect(() => {
        const onMsg = e => {
          const {type, payload} = e.data || ({});
          switch (type) {
            case "NAV":
              setRoute(payload.route);
              break;
            case "SELECT":
              setSelected(payload.appId);
              break;
            case "APPS_UPDATED":
              setApps(loadApps());
              break;
            case "CFG_UPDATED":
              setCfg(loadCfg());
              setToast(true);
              break;
            default:
              break;
          }
        };
        bc.addEventListener("message", onMsg);
        return () => bc.removeEventListener("message", onMsg);
      }, [bc]);
      const nav = nextRoute => {
        setRoute(nextRoute);
        bc.postMessage({
          type: "NAV",
          payload: {
            route: nextRoute
          }
        });
      };
      const selectApp = appId => {
        setSelected(appId);
        bc.postMessage({
          type: "SELECT",
          payload: {
            appId
          }
        });
      };
      const onCreate = name => {
        const id = uid();
        const next = [...apps, {
          id,
          name: name || "Sin título"
        }];
        setApps(next);
        saveApps(next);
        bc.postMessage({
          type: "APPS_UPDATED"
        });
        selectApp(id);
        nav("integrate");
      };
      const onSaveCfg = (appId, data) => {
        const next = {
          ...cfg,
          [appId]: data
        };
        setCfg(next);
        saveCfg(next);
        setToast(true);
        bc.postMessage({
          type: "CFG_UPDATED"
        });
      };
      return <div>
          {route === "menu" && <Menu onCreate={() => nav("create")} onIntegrate={() => nav("integrate")} />}

          {route === "create" && <CreateForm onCancel={() => nav("menu")} onSave={onCreate} />}

          {route === "integrate" && <IntegrateForm apps={apps} selected={selected} onSelect={selectApp} saved={cfg[selected]} onSave={data => onSaveCfg(selected, data)} onCancel={() => nav("menu")} />}

          <Toast open={toast} onClose={() => setToast(false)}>
            Successfully saved your changes.
          </Toast>
        </div>;
    }
    function Menu({onCreate, onIntegrate}) {
      return <ul className="space-y-4 list-none login_list">
          <li className="list-none !px-0">
            <button onClick={onCreate} className="w-full text-left">
              <Card className="p-5 hover:shadow-md transition">
                <div className="flex items-center justify-between">
                  <div className="flex items-center gap-4">
                    <IconTile>
                      <LightningIcon />
                    </IconTile>
                    <h2 className="text-lg">Crear una nueva aplicación</h2>
                  </div>
                  <RightChevron className="w-4 h-4 text-zinc-500" />
                </div>
              </Card>
            </button>
          </li>
          <li className="list-none !px-0">
            <button onClick={onIntegrate} className="w-full text-left">
              <Card className="p-5 hover:shadow-md transition">
                <div className="flex items-center justify-between">
                  <div className="flex items-center gap-4">
                    <IconTile>
                      <LayersIcon />
                    </IconTile>
                    <h2 className="text-lg">Integrar con una aplicación existente</h2>
                  </div>
                  <RightChevron className="w-4 h-4 text-zinc-500" />
                </div>
              </Card>
            </button>
          </li>
          <li className="list-none !px-0">
            <a className="no_external_icon block" href={sampleApp ? sampleApp : "/"} target="_blank" rel="noreferrer">
              <Card className="p-5 hover:shadow-md transition">
                <div className="flex items-center justify-between">
                  <div className="flex items-center gap-4">
                    <IconTile>
                      <GithubIcon />
                    </IconTile>
                    <h2 className="text-lg">Ver una aplicación de ejemplo</h2>
                  </div>
                  <RightChevron className="w-4 h-4 text-zinc-500" />
                </div>
              </Card>
            </a>
          </li>
        </ul>;
    }
    function CreateForm({onSave, onCancel}) {
      const [name, setName] = useState("");
      return <div className="space-y-6">
          <Input id="app-name" label="Nombre de la aplicación" placeholder="Mi aplicación" value={name} onChange={setName} />
          <p className="text-sm text-zinc-500">Puedes cambiarlo más adelante en la configuración de la aplicación.</p>
          <div className="flex gap-3">
            <Button onClick={() => onSave(name)}>Guardar</Button>
            <Button variant="outline" onClick={onCancel}>
              Cancelar
            </Button>
          </div>
        </div>;
    }
    function IntegrateForm({apps, selected, onSelect, saved, onSave, onCancel}) {
      const [callbacks, setCallbacks] = useState(saved?.callbacks ?? "");
      const [logouts, setLogouts] = useState(saved?.logouts ?? "");
      const [origins, setOrigins] = useState(saved?.origins ?? "");
      useEffect(() => {
        setCallbacks(loadCfg()[selected]?.callbacks ?? "");
        setLogouts(loadCfg()[selected]?.logouts ?? "");
        setOrigins(loadCfg()[selected]?.origins ?? "");
      }, [selected]);
      return <div className="space-y-6">
          <div>
            <span className="block text-sm text-zinc-600 dark:text-zinc-300 mb-1">Selecciona tu aplicación</span>
            <Select label="" value={selected} onChange={onSelect} options={apps} />
          </div>

          <form className="space-y-4" onSubmit={e => {
        e.preventDefault();
        onSave({
          callbacks,
          logouts,
          origins
        });
      }}>
            <Input id="callbacks" name="callbacks" label="URLs de callback" placeholder="http://localhost:3000" value={callbacks} onChange={setCallbacks} />
            <Input id="logout" name="allowed_logout_urls" label="URLs de cierre de sesión" placeholder="http://localhost:3000" value={logouts} onChange={setLogouts} />
            <Input id="origins" name="web_origins" label="Orígenes web permitidos" placeholder="http://localhost:3000" value={origins} onChange={setOrigins} />

            <div className="flex gap-3 pt-2">
              <Button type="submit">Guardar</Button>
              <Button variant="outline" type="button" onClick={onCancel}>
                Cancelar
              </Button>
            </div>
          </form>
        </div>;
    }
    return <div className="w-full mx-auto py-8">
        <Flows />
      </div>;
  }
  function SignUpFormInternal() {
    return <div className="flex flex-col gap-2 items-center h-full">
        <img noZoom src="/docs/img/quickstarts/action_hero_dashboard.svg" alt="Regístrate para obtener una cuenta de Auth0" style={{
      width: "250px",
      height: "250px"
    }} />
        <span className="text-center" style={{
      width: "400px"
    }}>
          Regístrate para obtener una{" "}
          <a href="https://auth0.com/signup" target="_blank" rel="noopener noreferrer">
            cuenta de Auth0
          </a>{" "}
          o{" "}
          <span className="font-semibold text-primary dark:text-white cursor-pointer" onClick={() => console.log("log in")}>
            inicia sesión
          </span>{" "}
          en tu cuenta existente para integrarte directamente con tu propio tenant.
        </span>
        <button onClick={() => console.log("sign up")} className="bg-primary dark:bg-primary-light text-white dark:text-black px-4 py-2 rounded-md mt-4 font-medium" style={{
      width: "140px"
    }}>
          Regístrate
        </button>
      </div>;
  }
  return <></>;
};

export const SideMenuSectionItem = ({id, children}) => {
  return <div id={`side-menu-item-${id}`} className="recipe-side-menu-item flex flex-col w-full h-full">
      {children}
    </div>;
};

export const SideMenu = ({sections, children}) => {
  const [visibleSection, setVisibleSection] = useState(sections[0]?.id ?? null);
  const checkVisibility = () => {
    let currentVisible = null;
    const viewportHeight = window.innerHeight;
    const scrollY = window.scrollY;
    sections.forEach(({id}) => {
      const section = document.getElementById(id);
      if (section) {
        const rect = section.getBoundingClientRect();
        const sectionTop = rect.top + scrollY;
        const sectionBottom = sectionTop + rect.height;
        const multiplier = viewportHeight > 1600 ? 0.34 : 0.22;
        if (scrollY + viewportHeight * multiplier >= sectionTop && scrollY <= sectionBottom) {
          currentVisible = id;
        }
      }
    });
    if (currentVisible && currentVisible !== visibleSection) {
      setVisibleSection(currentVisible);
    }
  };
  useEffect(() => {
    const throttledCheck = () => {
      setTimeout(checkVisibility, 100);
    };
    checkVisibility();
    window.addEventListener("scroll", throttledCheck);
    return () => {
      window.removeEventListener("scroll", throttledCheck);
    };
  }, [sections, visibleSection]);
  useEffect(() => {
    sections.forEach(({id}) => {
      const section = document.getElementById(id);
      const sideMenuItem = document.getElementById(`side-menu-item-${id}`);
      if (section) {
        if (id === visibleSection) {
          section.classList.add("active-section");
        } else {
          section.classList.remove("active-section");
        }
      }
      if (sideMenuItem) {
        if (id === visibleSection) {
          sideMenuItem.classList.add("active-side-menu-item");
        } else {
          sideMenuItem.classList.remove("active-side-menu-item");
        }
      }
    });
  }, [visibleSection, sections]);
  return <div className="recipe-side-menu sticky px-2 py-1" style={{
    height: "calc(100vh - 7rem)",
    top: "7rem",
    scrollMarginTop: "var(--scroll-mt)"
  }}>
      {children.map(child => {
    if (child.props.id === visibleSection) {
      return child;
    }
    return null;
  })}
    </div>;
};

export const Section = ({id, title, stepNumber, children, isSingleColumn = false}) => {
  return <div id={id} className={`recipe-section flex flex-col transition-opacity duration-200`}>
      {}
      <Step title={title} stepNumber={stepNumber} titleSize="h3">
        {children}
      </Step>
    </div>;
};

export const Content = ({title, children}) => {
  return <div className="recipe-content flex flex-col">
      {title && <h1 className="text-3xl">{title}</h1>}
      {children}
    </div>;
};

export const Recipe = ({children, isSingleColumn = false}) => {
  return <div className={`pl-4 recipe-container mx-auto grid grid-cols-1 gap-10 relative ${isSingleColumn ? "md:grid-cols-1" : "md:grid-cols-2"}`}>
      {children}
    </div>;
};

<QuickstartButtons githubLink="https://github.com/auth0-samples/auth0-php-web-app/tree/main/app" />

export const sections = [{
  id: "configure-auth0",
  title: "Configurar Auth0"
}, {
  id: "install-the-auth0-php-sdk",
  title: "Instalar el SDK de Auth0 para PHP"
}, {
  id: "create-routes",
  title: "Crear rutas"
}, {
  id: "add-login-to-your-application",
  title: "Agregar el inicio de sesión a tu aplicación"
}, {
  id: "add-logout-to-your-application",
  title: "Agregar el cierre de sesión a tu aplicación"
}, {
  id: "show-user-profile-information",
  title: "Mostrar información del perfil de usuario"
}];

<Recipe>
  <Content>
    Auth0 te permite agregar autenticación a casi cualquier tipo de aplicación de forma rápida. Esta guía muestra cómo
    integrar Auth0, agregar autenticación y mostrar información del perfil del usuario en cualquier aplicación PHP con el Auth0 PHP
    SDK.

    Para usar este inicio rápido, necesitarás:

    <Section id={sections[0].id} title={sections[0].title} stepNumber="1">
      Para usar los servicios de Auth0, necesitas tener una aplicación configurada en el Auth0 Dashboard. La aplicación de Auth0 es
      donde configurarás cómo quieres que funcione la autenticación para el proyecto que estás desarrollando.

      ### Configurar una aplicación

      Usa el selector interactivo para crear una nueva aplicación de Auth0 o seleccionar una aplicación existente que represente
      el proyecto que quieres integrar. A cada aplicación en Auth0 se le asigna un ID de cliente alfanumérico único
      que el código de tu aplicación usará para llamar a las API de Auth0 mediante el SDK.

      Cualquier ajuste que configures con esta guía de inicio rápido se actualizará automáticamente en tu aplicación en el [Dashboard](https://manage.auth0.com/#/), que es donde
      podrás administrar tus aplicaciones más adelante.

      Si prefieres explorar una configuración completa, también puedes ver una aplicación de ejemplo.

      ### Configurar URL de devolución de llamada

      Una URL de devolución de llamada es una URL de tu aplicación a la que quieres que Auth0 redirija a los usuarios después de que se hayan
      autenticado. Si no se configura, los usuarios no volverán a tu aplicación después de iniciar sesión.

      <Info>
        Si estás siguiendo nuestro proyecto de ejemplo, establece esto en
        `http://localhost:3000/callback`.
      </Info>

      ### Configurar URL de cierre de sesión

      Una URL de cierre de sesión es una URL de tu aplicación a la que quieres que Auth0 redirija a los usuarios después de que hayan cerrado
      sesión. Si no se configura, los usuarios no podrán cerrar sesión en tu aplicación y recibirán un error.

      <Info>
        Si estás siguiendo nuestro proyecto de ejemplo, establece esto en `http://localhost:3000`.
      </Info>

      ### Configurar orígenes web permitidos

      Un origen web permitido es una URL a la que quieres permitir el acceso a tu flujo de autenticación. Debe
      incluir la URL de tu proyecto. Si no se configura correctamente, tu proyecto no podrá renovar silenciosamente
      los tokens de autenticación, por lo que los usuarios cerrarán sesión la próxima vez que visiten tu aplicación o actualicen una
      página.

      <Info>
        Si estás siguiendo nuestro proyecto de ejemplo, establece esto en `http://localhost:3000`.
      </Info>
    </Section>

    <Section id={sections[1].id} title={sections[1].title} stepNumber="2">
      Auth0 proporciona un [SDK
      de PHP](https://github.com/auth0/auth0-PHP) (Auth0-PHP) para simplificar la implementación de la autenticación y la autorización de Auth0 en aplicaciones PHP.

      El SDK de PHP de Auth0 requiere que tengas instaladas bibliotecas HTTP compatibles con [PSR-17](https://www.php-fig.org/psr/psr-17/) y [PSR-18](https://www.php-fig.org/psr/psr-18/) para gestionar las solicitudes de red. Si
      no dispones de estas bibliotecas, puedes instalar opciones confiables ejecutando los siguientes comandos en tu
      terminal:

      ```text lines theme={null}
      cd <your-project-directory>
      composer require symfony/http-client nyholm/psr7
      ```

      Ahora, instala el SDK de PHP de Auth0 ejecutando el siguiente comando en la terminal:

      ```text lines theme={null}
      composer require auth0/auth0-php
      ```

      ### Configura el SDK de Auth0

      Crea un archivo nuevo en tu aplicación llamado `index.php` y copia en él el código del panel interactivo
      de la derecha, en la pestaña **index.php**.

      Para que el SDK funcione correctamente, debes configurar las siguientes propiedades en el SDK de Auth0 durante la inicialización:

      * `domain`: El dominio de tu inquilino de Auth0. Por lo general, puedes encontrarlo en el Auth0 Dashboard,
        en la configuración de tu aplicación, en el campo Domain. Si usas un [dominio personalizado](https://auth0.com/docs/custom-domains), debes establecer este valor con el
        valor de tu dominio personalizado.
      * `clientId`: El ID de la aplicación de Auth0 que configuraste antes en esta guía de inicio rápido. Puedes encontrarlo
        en el Auth0 Dashboard, en la configuración de tu aplicación, en el campo Client ID.
      * `clientSecret`: El secreto de la aplicación de Auth0 que configuraste antes en esta guía de inicio rápido. Puedes
        encontrarlo en el Auth0 Dashboard, en la configuración de tu aplicación, en el campo Client Secret.
      * `redirectUri`: La URL de tu aplicación a la que quieres que Auth0 redirija a los usuarios después de
        autenticarse. Esto corresponde a la URL de callback que configuraste antes en esta guía de inicio rápido. También puedes
        encontrar este valor en el Auth0 Dashboard, en la configuración de tu aplicación, en el campo Callback URLs. Asegúrate de que
        lo que introduzcas en tu código coincida con lo que configuraste antes; de lo contrario, tus usuarios verán un error.
      * `cookieSecret`: Un valor secreto largo que se usa para cifrar la cookie de sesión. Puedes generar una
        cadena adecuada ejecutando `openssl rand -hex 32` en tu terminal.

      <Info>
        ##### Punto de control

        Tu SDK de Auth0 ahora debería estar correctamente configurado. Ejecuta tu aplicación para verificar que:

        * El SDK se inicializa correctamente.
        * Tu aplicación no genera ningún error relacionado con Auth0.
      </Info>
    </Section>

    <Section id={sections[2].id} title={sections[2].title} stepNumber="3">
      Ahora instale una biblioteca de enrutamiento para ayudar a dirigir las solicitudes entrantes a su aplicación. Este no es un paso obligatorio,
      pero simplifica la estructura de la aplicación para los fines de esta guía de inicio rápido.

      ```text lines theme={null}
      composer require steampixel/simple-php-router
      ```

      Cree un archivo nuevo en su aplicación llamado `router.php` para definir las rutas y copie el código
      desde el panel interactivo de la derecha.
    </Section>

    <Section id={sections[3].id} title={sections[3].title} stepNumber="4">
      Ahora que ha configurado su aplicación de Auth0 y el SDK de Auth0 para PHP, debe configurar el inicio de sesión en su
      proyecto. Para ello, usará el método `login()` del SDK para crear un botón de inicio de sesión que redirija a los
      usuarios a la página de Universal Login de Auth0. Después de que un usuario se autentique correctamente, se le redirigirá a la
      URL de devolución de llamada que configuró anteriormente en esta guía de inicio rápido.

      Cree un archivo nuevo en su aplicación llamado `login.php` para gestionar el proceso de inicio de sesión y copie en él el
      código del panel interactivo de la derecha, que contiene la lógica necesaria para iniciar sesión.

      <Info>
        ##### Punto de control

        Ahora debería poder iniciar sesión o registrarse con un username y una contraseña.

        Haga clic en el enlace de inicio de sesión y verifique que:

        * Su aplicación le redirige a la página de Universal Login de Auth0.
        * Puede iniciar sesión o registrarse.
        * Auth0 le redirige de vuelta a su aplicación usando el valor de `redirectUri` que utilizó
          para configurar el SDK.
      </Info>
    </Section>

    <Section id={sections[4].id} title={sections[4].title} stepNumber="5">
      Los usuarios que inicien sesión en su proyecto también necesitarán una forma de cerrar sesión. Gestionaremos un botón para cerrar sesión mediante el método
      `logout()` del SDK. Cuando los usuarios cierren sesión, se les redirigirá al endpoint de [cierre de sesión de Auth0](https://auth0.com/docs/api/authentication?http#logout), que
      luego los redirigirá inmediatamente a la URL de cierre de sesión que configuró anteriormente en esta guía de inicio rápido.

      Cree un archivo nuevo en su aplicación llamado `logout.php` para gestionar el proceso y copie en él el
      código del panel interactivo, que contiene la lógica necesaria para cerrar sesión. Luego, actualice su
      archivo `index.php` para incluir el botón para cerrar sesión.

      <Info>
        ##### Punto de control

        Ejecute su aplicación y haga clic en el botón para cerrar sesión. Verifique que:

        * Su aplicación lo redirija a la dirección que especificó como una de las Allowed Logout URLs en la
          configuración de la aplicación.
        * Ya no haya iniciado sesión en su aplicación.
      </Info>
    </Section>

    <Section id={sections[5].id} title={sections[5].title} stepNumber="6">
      Ahora que sus usuarios pueden iniciar sesión y cerrar sesión, probablemente querrá recuperar la [información del perfil](https://auth0.com/docs/users/concepts/overview-user-profile)
      asociada a los usuarios autenticados. Por ejemplo, puede que quiera mostrar el nombre o la
      foto de perfil de un usuario que haya iniciado sesión en su proyecto.

      El SDK de Auth0 para PHP proporciona información del usuario mediante el método `getCredentials()`. Revise el
      código de `profile.php` en el panel interactivo para ver un ejemplo de cómo usarlo.

      Como el método contiene información confidencial relacionada con la identidad del usuario, su disponibilidad depende del
      estado de autenticación del usuario. Para evitar errores de renderizado, siempre debe comprobar si el
      método `getCredentials()` devuelve un `object` o `null` para determinar si
      Auth0 ha autenticado al usuario antes de que la aplicación procese los resultados.

      <Info>
        ##### Punto de control

        Verifique que:

        * Puede mostrar correctamente `nickname` o cualquier otra propiedad del usuario después de haber
          iniciado sesión.
      </Info>
    </Section>

    ## Próximos pasos

    ¡Excelente trabajo! Si llegaste hasta aquí, ya deberías tener el inicio de sesión, el cierre de sesión y la información del perfil de usuario funcionando en tu aplicación.

    Con esto concluye nuestro tutorial de inicio rápido, pero hay mucho más por explorar. Para saber más sobre lo que puedes hacer con Auth0, consulta:

    * [Auth0 Dashboard](https://manage.auth0.com/dashboard/us/dev-gja8kxz4ndtex3rq) - Aprende a configurar y gestionar tu inquilino y tus aplicaciones de Auth0
    * [Auth0-PHP SDK](https://github.com/auth0/auth0-php) - Explore con más detalle el SDK utilizado en este tutorial
    * [Auth0 Marketplace](https://marketplace.auth0.com/) - Descubra las integraciones que puede habilitar para ampliar las funcionalidades de Auth0
  </Content>

  <SideMenu sections={sections}>
    <SideMenuSectionItem id={sections[0].id}>
      <SignUpForm />
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[1].id}>
      <AuthCodeGroup>
        ```php index.php lines theme={null}
        <?php

          declare(strict_types=1);

          require('vendor/autoload.php');

          use Auth0\SDK\Auth0;
          use Auth0\SDK\Configuration\SdkConfiguration;

          $configuration = new SdkConfiguration(
            domain: '{yourDomain}',
            clientId: '{yourClientId}',
            clientSecret: '{yourClientSecret}',
            redirectUri: 'http://' . $_SERVER['HTTP_HOST'] . '/callback',
            cookieSecret: '4f60eb5de6b5904ad4b8e31d9193e7ea4a3013b476ddb5c259ee9077c05e1457'
          );

          $sdk = new Auth0($configuration);

          require('router.php');
        ```

        ```php login.php lines theme={null}
        <?php

          declare(strict_types=1);

          /**
           * Prepara la sesión de la aplicación y redirige a la página de Universal Login de Auth0.
           *
           * El usuario será redirigido a tu ruta de callback para completar el flujo de autenticación.
           */

          header(sprintf('Location: %s', $sdk->login()));
        ```

        ```php logout.php lines theme={null}
        <?php

          declare(strict_types=1);

          /**
           * Borra la sesión de la aplicación y redirige al endpoint de cierre de sesión de Auth0.
           *
           * El usuario será redirigido a tu ruta de índice a continuación.
           */

          header(sprintf('Location: %s', $sdk->logout()));
        ```

        ```php profile.php lines theme={null}
        <?php

          declare(strict_types=1);

          $session = $sdk->getCredentials();
          $authenticated = $session !== null;

          $template = [
            'name' => $authenticated ? $session->user['email'] : 'guest',
            'picture' => $authenticated ? $session->user['picture'] : null,
            'session' => $authenticated ? print_r($session, true) : '',
            'auth:route' => $authenticated ? 'logout' : 'login',
            'auth:text' => $authenticated ? 'out' : 'in',
          ];

          printf('<p>Welcome, %s.</p>', $template['name']);
          printf('<p><pre>%s</pre></p>', $template['session']);
          printf('<p><a href="/%s">Log %s</a></p>', $template['auth:route'], $template['auth:text']);
        ```

        ```php router.php lines  theme={null}
        <?php

          declare(strict_types=1);

          use Steampixel\Route;

          if ($_SERVER['HTTP_HOST'] !== 'localhost:3000') {
            die('<p>This quickstart is configured to be run from <a href="http://localhost:3000">http://localhost:3000</a>.</p>');
          }

          Route::add('/', function() use ($sdk) {
            require('profile.php');
          });

          Route::add('/login', function() use ($sdk) {
            require('login.php');
          });

          Route::add('/callback', function() use ($sdk) {
            require('callback.php');
          });

          Route::add('/logout', function() use ($sdk) {
            require('logout.php');
          });

          Route::run();
        ```

        ```php callback.php lines  theme={null}
        <?php

          declare(strict_types=1);

          /**
           * Al regresar del Auth0 Universal Login, es necesario realizar un intercambio de code mediante el método `exchange()`
           * para completar el flujo de autenticación. Este proceso configura la sesión para su uso por parte de la aplicación.
           *
           * Si tiene éxito, el usuario será redirigido de vuelta a la ruta de inicio.
           */

           $hasAuthenticated = isset($_GET['state']) && isset($_GET['code']);
           $hasAuthenticationFailure = isset($_GET['error']);

          // Cuando la autenticación es exitosa, el usuario final regresará con los valores ?state y ?code en su solicitud.
          if ($hasAuthenticated) {
            try {
              $sdk->exchange();
            } catch (\Throwable $th) {
              printf('Unable to complete authentication: %s', $th->getMessage());
              exit;
            }
          }

          // Cuando la autenticación no es exitosa, el usuario final regresará con un ?error en su solicitud.
          if ($hasAuthenticationFailure) {
            printf('Authentication failure: %s', htmlspecialchars(strip_tags(filter_input(INPUT_GET, 'error'))));
            exit;
          }

          // Sin acciones pendientes: redirigir a la ruta de inicio.
          header('Location: /');
        ```
      </AuthCodeGroup>
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[2].id}>
      <AuthCodeGroup>
        ```php router.php lines  theme={null}
        <?php

          declare(strict_types=1);

          use Steampixel\Route;

          if ($_SERVER['HTTP_HOST'] !== 'localhost:3000') {
            die('<p>This quickstart is configured to be run from <a href="http://localhost:3000">http://localhost:3000</a>.</p>');
          }

          Route::add('/', function() use ($sdk) {
            require('profile.php');
          });

          Route::add('/login', function() use ($sdk) {
            require('login.php');
          });

          Route::add('/callback', function() use ($sdk) {
            require('callback.php');
          });

          Route::add('/logout', function() use ($sdk) {
            require('logout.php');
          });

          Route::run();
        ```

        ```php index.php lines theme={null}
        <?php

          declare(strict_types=1);

          require('vendor/autoload.php');

          use Auth0\SDK\Auth0;
          use Auth0\SDK\Configuration\SdkConfiguration;

          $configuration = new SdkConfiguration(
            domain: '{yourDomain}',
            clientId: '{yourClientId}',
            clientSecret: '{yourClientSecret}',
            redirectUri: 'http://' . $_SERVER['HTTP_HOST'] . '/callback',
            cookieSecret: '4f60eb5de6b5904ad4b8e31d9193e7ea4a3013b476ddb5c259ee9077c05e1457'
          );

          $sdk = new Auth0($configuration);

          require('router.php');
        ```

        ```php login.php lines theme={null}
        <?php

          declare(strict_types=1);

          /**
           * Prepara la sesión de la aplicación y redirige a la página de Universal Login de Auth0.
           *
           * El usuario será redirigido a tu ruta de callback para completar el flujo de autenticación.
           */

          header(sprintf('Location: %s', $sdk->login()));
        ```

        ```php logout.php lines theme={null}
        <?php

          declare(strict_types=1);

          /**
           * Borra la sesión de la aplicación y redirige al endpoint de cierre de sesión de Auth0.
           *
           * El usuario será redirigido a tu ruta de índice a continuación.
           */

          header(sprintf('Location: %s', $sdk->logout()));
        ```

        ```php profile.php lines theme={null}
        <?php

          declare(strict_types=1);

          $session = $sdk->getCredentials();
          $authenticated = $session !== null;

          $template = [
            'name' => $authenticated ? $session->user['email'] : 'guest',
            'picture' => $authenticated ? $session->user['picture'] : null,
            'session' => $authenticated ? print_r($session, true) : '',
            'auth:route' => $authenticated ? 'logout' : 'login',
            'auth:text' => $authenticated ? 'out' : 'in',
          ];

          printf('<p>Welcome, %s.</p>', $template['name']);
          printf('<p><pre>%s</pre></p>', $template['session']);
          printf('<p><a href="/%s">Log %s</a></p>', $template['auth:route'], $template['auth:text']);
        ```

        ```php callback.php lines  theme={null}
        <?php

          declare(strict_types=1);

          /**
           * Al regresar del Auth0 Universal Login, es necesario realizar un intercambio de code mediante el método `exchange()`
           * para completar el flujo de autenticación. Este proceso configura la sesión para su uso por parte de la aplicación.
           *
           * Si tiene éxito, el usuario será redirigido de vuelta a la ruta de inicio.
           */

           $hasAuthenticated = isset($_GET['state']) && isset($_GET['code']);
           $hasAuthenticationFailure = isset($_GET['error']);

          // Cuando la autenticación es exitosa, el usuario final regresará con los valores ?state y ?code en su solicitud.
          if ($hasAuthenticated) {
            try {
              $sdk->exchange();
            } catch (\Throwable $th) {
              printf('Unable to complete authentication: %s', $th->getMessage());
              exit;
            }
          }

          // Cuando la autenticación no es exitosa, el usuario final regresará con un ?error en su solicitud.
          if ($hasAuthenticationFailure) {
            printf('Authentication failure: %s', htmlspecialchars(strip_tags(filter_input(INPUT_GET, 'error'))));
            exit;
          }

          // Sin acciones pendientes: redirigir a la ruta de inicio.
          header('Location: /');
        ```
      </AuthCodeGroup>
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[3].id}>
      <AuthCodeGroup>
        ```php login.php lines theme={null}
        <?php

          declare(strict_types=1);

          /**
           * Prepara la sesión de la aplicación y redirige a la página de Universal Login de Auth0.
           *
           * El usuario será redirigido a tu ruta de callback para completar el flujo de autenticación.
           */

          header(sprintf('Location: %s', $sdk->login()));
        ```

        ```php index.php lines theme={null}
        <?php

          declare(strict_types=1);

          require('vendor/autoload.php');

          use Auth0\SDK\Auth0;
          use Auth0\SDK\Configuration\SdkConfiguration;

          $configuration = new SdkConfiguration(
            domain: '{yourDomain}',
            clientId: '{yourClientId}',
            clientSecret: '{yourClientSecret}',
            redirectUri: 'http://' . $_SERVER['HTTP_HOST'] . '/callback',
            cookieSecret: '4f60eb5de6b5904ad4b8e31d9193e7ea4a3013b476ddb5c259ee9077c05e1457'
          );

          $sdk = new Auth0($configuration);

          require('router.php');
        ```

        ```php logout.php lines theme={null}
        <?php

          declare(strict_types=1);

          /**
           * Borra la sesión de la aplicación y redirige al endpoint de cierre de sesión de Auth0.
           *
           * El usuario será redirigido a tu ruta de índice a continuación.
           */

          header(sprintf('Location: %s', $sdk->logout()));
        ```

        ```php profile.php lines theme={null}
        <?php

          declare(strict_types=1);

          $session = $sdk->getCredentials();
          $authenticated = $session !== null;

          $template = [
            'name' => $authenticated ? $session->user['email'] : 'guest',
            'picture' => $authenticated ? $session->user['picture'] : null,
            'session' => $authenticated ? print_r($session, true) : '',
            'auth:route' => $authenticated ? 'logout' : 'login',
            'auth:text' => $authenticated ? 'out' : 'in',
          ];

          printf('<p>Welcome, %s.</p>', $template['name']);
          printf('<p><pre>%s</pre></p>', $template['session']);
          printf('<p><a href="/%s">Log %s</a></p>', $template['auth:route'], $template['auth:text']);
        ```

        ```php router.php lines  theme={null}
        <?php

          declare(strict_types=1);

          use Steampixel\Route;

          if ($_SERVER['HTTP_HOST'] !== 'localhost:3000') {
            die('<p>This quickstart is configured to be run from <a href="http://localhost:3000">http://localhost:3000</a>.</p>');
          }

          Route::add('/', function() use ($sdk) {
            require('profile.php');
          });

          Route::add('/login', function() use ($sdk) {
            require('login.php');
          });

          Route::add('/callback', function() use ($sdk) {
            require('callback.php');
          });

          Route::add('/logout', function() use ($sdk) {
            require('logout.php');
          });

          Route::run();
        ```

        ```php callback.php lines  theme={null}
        <?php

          declare(strict_types=1);

          /**
           * Al regresar del Auth0 Universal Login, es necesario realizar un intercambio de code mediante el método `exchange()`
           * para completar el flujo de autenticación. Este proceso configura la sesión para su uso por parte de la aplicación.
           *
           * Si tiene éxito, el usuario será redirigido de vuelta a la ruta de inicio.
           */

           $hasAuthenticated = isset($_GET['state']) && isset($_GET['code']);
           $hasAuthenticationFailure = isset($_GET['error']);

          // Cuando la autenticación es exitosa, el usuario final regresará con los valores ?state y ?code en su solicitud.
          if ($hasAuthenticated) {
            try {
              $sdk->exchange();
            } catch (\Throwable $th) {
              printf('Unable to complete authentication: %s', $th->getMessage());
              exit;
            }
          }

          // Cuando la autenticación no es exitosa, el usuario final regresará con un ?error en su solicitud.
          if ($hasAuthenticationFailure) {
            printf('Authentication failure: %s', htmlspecialchars(strip_tags(filter_input(INPUT_GET, 'error'))));
            exit;
          }

          // Sin acciones pendientes: redirigir a la ruta de inicio.
          header('Location: /');
        ```
      </AuthCodeGroup>
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[4].id}>
      <AuthCodeGroup>
        ```php logout.php lines theme={null}
        <?php

          declare(strict_types=1);

          /**
           * Borra la sesión de la aplicación y redirige al endpoint de cierre de sesión de Auth0.
           *
           * El usuario será redirigido a tu ruta de índice a continuación.
           */

          header(sprintf('Location: %s', $sdk->logout()));
        ```

        ```php index.php lines theme={null}
        <?php

          declare(strict_types=1);

          require('vendor/autoload.php');

          use Auth0\SDK\Auth0;
          use Auth0\SDK\Configuration\SdkConfiguration;

          $configuration = new SdkConfiguration(
            domain: '{yourDomain}',
            clientId: '{yourClientId}',
            clientSecret: '{yourClientSecret}',
            redirectUri: 'http://' . $_SERVER['HTTP_HOST'] . '/callback',
            cookieSecret: '4f60eb5de6b5904ad4b8e31d9193e7ea4a3013b476ddb5c259ee9077c05e1457'
          );

          $sdk = new Auth0($configuration);

          require('router.php');
        ```

        ```php login.php lines theme={null}
        <?php

          declare(strict_types=1);

          /**
           * Prepara la sesión de la aplicación y redirige a la página de Universal Login de Auth0.
           *
           * El usuario será redirigido a tu ruta de callback para completar el flujo de autenticación.
           */

          header(sprintf('Location: %s', $sdk->login()));
        ```

        ```php profile.php lines theme={null}
        <?php

          declare(strict_types=1);

          $session = $sdk->getCredentials();
          $authenticated = $session !== null;

          $template = [
            'name' => $authenticated ? $session->user['email'] : 'guest',
            'picture' => $authenticated ? $session->user['picture'] : null,
            'session' => $authenticated ? print_r($session, true) : '',
            'auth:route' => $authenticated ? 'logout' : 'login',
            'auth:text' => $authenticated ? 'out' : 'in',
          ];

          printf('<p>Welcome, %s.</p>', $template['name']);
          printf('<p><pre>%s</pre></p>', $template['session']);
          printf('<p><a href="/%s">Log %s</a></p>', $template['auth:route'], $template['auth:text']);
        ```

        ```php router.php lines  theme={null}
        <?php

          declare(strict_types=1);

          use Steampixel\Route;

          if ($_SERVER['HTTP_HOST'] !== 'localhost:3000') {
            die('<p>This quickstart is configured to be run from <a href="http://localhost:3000">http://localhost:3000</a>.</p>');
          }

          Route::add('/', function() use ($sdk) {
            require('profile.php');
          });

          Route::add('/login', function() use ($sdk) {
            require('login.php');
          });

          Route::add('/callback', function() use ($sdk) {
            require('callback.php');
          });

          Route::add('/logout', function() use ($sdk) {
            require('logout.php');
          });

          Route::run();
        ```

        ```php callback.php lines  theme={null}
        <?php

          declare(strict_types=1);

          /**
           * Al regresar del Auth0 Universal Login, es necesario realizar un intercambio de code mediante el método `exchange()`
           * para completar el flujo de autenticación. Este proceso configura la sesión para su uso por parte de la aplicación.
           *
           * Si tiene éxito, el usuario será redirigido de vuelta a la ruta de inicio.
           */

           $hasAuthenticated = isset($_GET['state']) && isset($_GET['code']);
           $hasAuthenticationFailure = isset($_GET['error']);

          // Cuando la autenticación es exitosa, el usuario final regresará con los valores ?state y ?code en su solicitud.
          if ($hasAuthenticated) {
            try {
              $sdk->exchange();
            } catch (\Throwable $th) {
              printf('Unable to complete authentication: %s', $th->getMessage());
              exit;
            }
          }

          // Cuando la autenticación no es exitosa, el usuario final regresará con un ?error en su solicitud.
          if ($hasAuthenticationFailure) {
            printf('Authentication failure: %s', htmlspecialchars(strip_tags(filter_input(INPUT_GET, 'error'))));
            exit;
          }

          // Sin acciones pendientes: redirigir a la ruta de inicio.
          header('Location: /');
        ```
      </AuthCodeGroup>
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[5].id}>
      <AuthCodeGroup>
        ```php profile.php lines theme={null}
        <?php

          declare(strict_types=1);

          $session = $sdk->getCredentials();
          $authenticated = $session !== null;

          $template = [
            'name' => $authenticated ? $session->user['email'] : 'guest',
            'picture' => $authenticated ? $session->user['picture'] : null,
            'session' => $authenticated ? print_r($session, true) : '',
            'auth:route' => $authenticated ? 'logout' : 'login',
            'auth:text' => $authenticated ? 'out' : 'in',
          ];

          printf('<p>Welcome, %s.</p>', $template['name']);
          printf('<p><pre>%s</pre></p>', $template['session']);
          printf('<p><a href="/%s">Log %s</a></p>', $template['auth:route'], $template['auth:text']);
        ```

        ```php index.php lines theme={null}
        <?php

          declare(strict_types=1);

          require('vendor/autoload.php');

          use Auth0\SDK\Auth0;
          use Auth0\SDK\Configuration\SdkConfiguration;

          $configuration = new SdkConfiguration(
            domain: '{yourDomain}',
            clientId: '{yourClientId}',
            clientSecret: '{yourClientSecret}',
            redirectUri: 'http://' . $_SERVER['HTTP_HOST'] . '/callback',
            cookieSecret: '4f60eb5de6b5904ad4b8e31d9193e7ea4a3013b476ddb5c259ee9077c05e1457'
          );

          $sdk = new Auth0($configuration);

          require('router.php');
        ```

        ```php login.php lines theme={null}
        <?php

          declare(strict_types=1);

          /**
           * Prepara la sesión de la aplicación y redirige a la página de Universal Login de Auth0.
           *
           * El usuario será redirigido a tu ruta de callback para completar el flujo de autenticación.
           */

          header(sprintf('Location: %s', $sdk->login()));
        ```

        ```php logout.php lines theme={null}
        <?php

          declare(strict_types=1);

          /**
           * Borra la sesión de la aplicación y redirige al endpoint de cierre de sesión de Auth0.
           *
           * El usuario será redirigido a tu ruta de índice a continuación.
           */

          header(sprintf('Location: %s', $sdk->logout()));
        ```

        ```php router.php lines  theme={null}
        <?php

          declare(strict_types=1);

          use Steampixel\Route;

          if ($_SERVER['HTTP_HOST'] !== 'localhost:3000') {
            die('<p>This quickstart is configured to be run from <a href="http://localhost:3000">http://localhost:3000</a>.</p>');
          }

          Route::add('/', function() use ($sdk) {
            require('profile.php');
          });

          Route::add('/login', function() use ($sdk) {
            require('login.php');
          });

          Route::add('/callback', function() use ($sdk) {
            require('callback.php');
          });

          Route::add('/logout', function() use ($sdk) {
            require('logout.php');
          });

          Route::run();
        ```

        ```php callback.php lines  theme={null}
        <?php

          declare(strict_types=1);

          /**
           * Al regresar del Auth0 Universal Login, es necesario realizar un intercambio de code mediante el método `exchange()`
           * para completar el flujo de autenticación. Este proceso configura la sesión para su uso por parte de la aplicación.
           *
           * Si tiene éxito, el usuario será redirigido de vuelta a la ruta de inicio.
           */

           $hasAuthenticated = isset($_GET['state']) && isset($_GET['code']);
           $hasAuthenticationFailure = isset($_GET['error']);

          // Cuando la autenticación es exitosa, el usuario final regresará con los valores ?state y ?code en su solicitud.
          if ($hasAuthenticated) {
            try {
              $sdk->exchange();
            } catch (\Throwable $th) {
              printf('Unable to complete authentication: %s', $th->getMessage());
              exit;
            }
          }

          // Cuando la autenticación no es exitosa, el usuario final regresará con un ?error en su solicitud.
          if ($hasAuthenticationFailure) {
            printf('Authentication failure: %s', htmlspecialchars(strip_tags(filter_input(INPUT_GET, 'error'))));
            exit;
          }

          // Sin acciones pendientes: redirigir a la ruta de inicio.
          header('Location: /');
        ```
      </AuthCodeGroup>
    </SideMenuSectionItem>
  </SideMenu>
</Recipe>
