> ## Documentation Index
> Fetch the complete documentation index at: https://auth0-docs-event-stream-action-templates.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Flux d’autorisation d’appareil

> Ce tutoriel explique comment appeler votre API à partir d’un appareil dont les entrées sont limitées, à l’aide du flux d’autorisation d’appareil.

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 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)}>Save</Button>
          <Button variant="outline" onClick={onCancel}>
            Cancel
          </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">Select your Application</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="Callback URLs" placeholder="http://localhost:3000" value={callbacks} onChange={setCallbacks} />
          <Input id="logout" name="allowed_logout_urls" label="Logout URLs" placeholder="http://localhost:3000" value={logouts} onChange={setLogouts} />
          <Input id="origins" name="web_origins" label="Allowed Web Origins" placeholder="http://localhost:3000" value={origins} onChange={setOrigins} />

          <div className="flex gap-3 pt-2">
            <Button type="submit">Save</Button>
            <Button variant="outline" type="button" onClick={onCancel}>
              Cancel
            </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: "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)}>Save</Button>
            <Button variant="outline" onClick={onCancel}>
              Cancel
            </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">Select your Application</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="Callback URLs" placeholder="http://localhost:3000" value={callbacks} onChange={setCallbacks} />
            <Input id="logout" name="allowed_logout_urls" label="Logout URLs" placeholder="http://localhost:3000" value={logouts} onChange={setLogouts} />
            <Input id="origins" name="web_origins" label="Allowed Web Origins" placeholder="http://localhost:3000" value={origins} onChange={setOrigins} />

            <div className="flex gap-3 pt-2">
              <Button type="submit">Save</Button>
              <Button variant="outline" type="button" onClick={onCancel}>
                Cancel
              </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="Sign up for an Auth0 account" style={{
      width: "250px",
      height: "250px"
    }} />
        <span className="text-center" style={{
      width: "400px"
    }}>
          Sign up for an{" "}
          <a href="https://auth0.com/signup" target="_blank" rel="noopener noreferrer">
            Auth0 account
          </a>{" "}
          or{" "}
          <span className="font-semibold text-primary dark:text-white cursor-pointer" onClick={() => console.log("log in")}>
            log in
          </span>{" "}
          to your existing account to integrate directly with your own 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"
    }}>
          Sign up
        </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>;
};

export const sections = [{
  id: "conditions-requises",
  title: "Conditions requises"
}, {
  id: "recevoir-le-code-de-l-appareil",
  title: "Recevoir le code de l’appareil"
}, {
  id: "recevoir-le-code-de-l-appareil",
  title: "Recevoir le code de l’appareil"
}, {
  id: "demande-d-activation-de-l-appareil",
  title: "Demande d’activation de l’appareil"
}, {
  id: "interrogation-du-point-de-terminaison-du-jeton",
  title: "Interrogation du point de terminaison du jeton"
}, {
  id: "autorisation-de-l-utilisateur",
  title: "Autorisation de l’utilisateur"
}, {
  id: "recevoir-les-jetons",
  title: "Recevoir les jetons"
}, {
  id: "appeler-votre-api",
  title: "Appeler votre API"
}, {
  id: "jetons-d-actualisation",
  title: "Jetons d’actualisation"
}, {
  id: "dépannage",
  title: "Dépannage"
}, {
  id: "exemples-de-mises-en-œuvre",
  title: "Exemples de mises en œuvre"
}, {
  id: "limites",
  title: "Limites"
}];

<Recipe>
  <Content>
    Ce tutoriel explique comment appeler votre API à partir d’un appareil dont les entrées sont limitées, à l’aide du flux d’autorisation d’appareil. Nous vous recommandons de vous connecter pour suivre ce démarrage rapide avec les exemples configurés pour votre compte.

    Pour une expérience interactive, vous pouvez utiliser [Terrain de jeu du flux d’appareil](https://auth0.github.io/device-flow-playground/).

    <Section id={sections[0].id} title={sections[0].title} stepNumber="1">
      * Enregistrez une application native.
      * Assurez-vous que l’option **Conforme à l’OIDC** est activée. Pour plus d’informations, consultez Authentification conforme à OIDC.
      * Ajoutez **Device Code (Code de l’appareil)** aux types d’autorisation de l’application. Pour plus d’informations, consultez Mettre à jour les types d’autorisation.
      * Ajoutez **Refresh Token (Jeton d’actualisation)** aux types d’autorisation de l’application si vous souhaitez activer les jetons d’actualisation.
      * Configurez et activez au moins une connexion pour l’application.
      * Enregistrez votre application avec Auth0.

        * Activez l’option **Autoriser l’accès hors ligne** si vous utilisez des jetons d’actualisation. Pour en savoir plus, veuillez consulter Paramètres API.
      * Configure Device User Code Settings (Configurez les paramètres du code utilisateur de l’appareil) pour définir le jeu de caractères, le format et la longueur de votre code utilisateur généré de manière aléatoire.
    </Section>

    <Section id={sections[1].id} title={sections[1].title} stepNumber="2">
      Lorsque l’utilisateur démarre l’application de l’appareil et souhaite l’autoriser, votre application doit demander un code d’appareil à Auth0 Authentication API pour l’associer à la session de l’utilisateur.

      Pour obtenir le code de l’appareil, votre application doit appeler le [Authorize endpoint (Point de terminaison d’autorisation)](/docs/api/authentication#-post-oauth-device-code-) d’Authentication API du flux d’autorisation de l’appareil :

      <AuthCodeGroup>
        ```bash cURL lines theme={null}
        curl --request post \
          --url 'https://{yourDomain}/oauth/device/code' \
          --header 'content-type: application/x-www-form-urlencoded'
        ```

        ```csharp C# lines theme={null}
        var client = new RestClient("https://{yourDomain}/oauth/device/code");
        var request = new RestRequest(Method.POST);
        request.AddHeader("content-type", "application/x-www-form-urlencoded");
        IRestResponse response = client.Execute(request);
        ```

        ```go Go lines  theme={null}
        package main
        import (
        "fmt"
        "net/http"
        "io/ioutil"
        )
        func main() {
        url := "https://{yourDomain}/oauth/device/code"
        req, _ := http.NewRequest("post", url, nil)
        req.Header.Add("content-type", "application/x-www-form-urlencoded")
        res, _ := http.DefaultClient.Do(req)
        defer res.Body.Close()
        body, _ := ioutil.ReadAll(res.Body)
        fmt.Println(res)
        fmt.Println(string(body))
        }
        ```

        ```java Java lines theme={null}
        HttpResponse<String> response = Unirest.post("https://{yourDomain}/oauth/device/code")
          .header("content-type", "application/x-www-form-urlencoded")
          .asString();
        ```

        ```javascript Node.JS lines theme={null}
        var axios = require("axios").default;
        var options = {
        method: 'post',
        url: 'https://{yourDomain}/oauth/device/code',
        headers: {'content-type': 'application/x-www-form-urlencoded'}
        };
        axios.request(options).then(function (response) {
        console.log(response.data);
        }).catch(function (error) {
        console.error(error);
        });
        ```

        ```objc Obj-C lines  theme={null}
        #import <Foundation/Foundation.h>
        NSDictionary *headers = @{ @"content-type": @"application/x-www-form-urlencoded" };
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://{yourDomain}/oauth/device/code"]
                                                          cachePolicy:NSURLRequestUseProtocolCachePolicy

                                                      timeoutInterval:10.0];

        [request setHTTPMethod:@"post"];
        [request setAllHTTPHeaderFields:headers];
        NSURLSession *session = [NSURLSession sharedSession];
        NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                                completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {

                                                    if (error) {

                                                        NSLog(@&quot;%@&quot;, error);

                                                    } else {

                                                        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;

                                                        NSLog(@&quot;%@&quot;, httpResponse);

                                                    }

                                                }];

        [dataTask resume];
        ```

        ```php PHP lines  theme={null}
        $curl = curl_init();
        curl_setopt_array($curl, [
        CURLOPT_URL => "https://{yourDomain}/oauth/device/code",
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING => "",
        CURLOPT_MAXREDIRS => 10,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_CUSTOMREQUEST => "post",
        CURLOPT_HTTPHEADER => [
        &quot;content-type: application/x-www-form-urlencoded&quot;

        ],
        ]);
        $response = curl_exec($curl);
        $err = curl_error($curl);
        curl_close($curl);
        if ($err) {
        echo "cURL Error #:" . $err;
        } else {
        echo $response;
        }
        ```

        ```python Python lines theme={null}
        import http.client
        conn = http.client.HTTPSConnection("")
        headers = { 'content-type': "application/x-www-form-urlencoded" }
        conn.request("post", "/{yourDomain}/oauth/device/code", headers=headers)
        res = conn.getresponse()
        data = res.read()
        print(data.decode("utf-8"))
        ```

        ```ruby Ruby lines theme={null}
        require 'uri'
        require 'net/http'
        require 'openssl'
        url = URI("https://{yourDomain}/oauth/device/code")
        http = Net::HTTP.new(url.host, url.port)
        http.use_ssl = true
        http.verify_mode = OpenSSL::SSL::VERIFY_NONE
        request = Net::HTTP::Post.new(url)
        request["content-type"] = 'application/x-www-form-urlencoded'
        response = http.request(request)
        puts response.read_body
        ```

        ```swift Swift lines  theme={null}
        import Foundation
        let headers = ["content-type": "application/x-www-form-urlencoded"]
        let request = NSMutableURLRequest(url: NSURL(string: "https://{yourDomain}/oauth/device/code")! as URL,
                                            cachePolicy: .useProtocolCachePolicy,

                                        timeoutInterval: 10.0)

        request.httpMethod = "post"
        request.allHTTPHeaderFields = headers
        let session = URLSession.shared
        let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
        if (error != nil) {
        print(error)

        } else {
        let httpResponse = response as? HTTPURLResponse

        print(httpResponse)

        }
        })
        dataTask.resume()
        ```
      </AuthCodeGroup>
    </Section>

    <Section id={sections[2].id} title={sections[2].title} stepNumber="3">
      L’application de l’appareil devrait recevoir une réponse HTTP 200 et une charge utile similaire à celle-ci :

      ```
      {
      "device_code": "GmRh...k9eS",
      "user_code": "WDJB-MJHT",
      "verification_uri": "https://my-tenant.auth0.com/device",
      "verification_uri_complete": "https://my-tenant.auth0.com/device?user_code=WDJB-MJHT",
      "expires_in": 900,
      "interval": 5
      }
      ```
    </Section>

    <Section id={sections[3].id} title={sections[3].title} stepNumber="4">
      Après avoir reçu le `device_code` et le `user_code`, votre application doit demander à l’utilisateur de se rendre au `verification_uri` et de saisir le `user_code`.

      <Frame>
        <img src="https://mintlify.s3.us-west-1.amazonaws.com/auth0-docs-event-stream-action-templates/docs/images/fr-ca/cdy7uua7fh8z/3Q9q41wocl6SojRoiGefXT/a98582a3c86740aaeb3d957f2dc4afe6/request-device-activation.png" alt="null" />
      </Frame>

      <Warning>
        Le `device\_code` n’est pas destiné directement à l’utilisateur et ne doit pas être affiché pendant l’interaction afin de ne pas créer de confusion chez l’utilisateur.
      </Warning>

      <Warning>
        Lorsque vous créez une CLI, vous pouvez ignorer cette étape et ouvrir directement le navigateur avec `verification\_uri\_complete`.
      </Warning>
    </Section>

    <Section id={sections[4].id} title={sections[4].title} stepNumber="5">
      Pendant que votre application attend que l’utilisateur l’active, elle doit appeler le [point de terminaison POST /oauth/token](/docs/api/authentication#-post-oauth-token-) d’Authentication API de manière intermittente et traiter la réponse de manière appropriée.

      <Info>
        Assurez-vous que votre application attend la durée de `interval` (en secondes) ou jusqu’à ce qu’elle reçoive une réponse positive, la durée la plus longue étant retenue, afin d’éviter les problèmes de latence du réseau.
      </Info>

      ```
      curl --request POST \
      --url 'https://{yourDomain}/oauth/token' \
      --header 'content-type: application/x-www-form-urlencoded' \
      --data grant_type=urn:ietf:params:oauth:grant-type:device_code \
      --data device_code=AUTH0_SCOPES \
      --data 'client_id={yourClientId}'
      ```
    </Section>

    <Section id={sections[5].id} title={sections[5].title} stepNumber="6">
      L’utilisateur peut soit balayer le code QR, soit ouvrir la page d’activation et saisir le code d’utilisateur :

      <Frame>
        <img src="https://mintlify.s3.us-west-1.amazonaws.com/auth0-docs-event-stream-action-templates/docs/images/fr-ca/cdy7uua7fh8z/7IwrVX4s5a36CvfY95rKCo/e0d5c2d9f1cb83993ee77d6e9499cfa7/Device_Activation_-_French.png" alt="null" />
      </Frame>

      Une page de confirmation s’affiche pour que l’utilisateur confirme qu’il s’agit du bon appareil :

      <Frame>
        <img src="https://mintlify.s3.us-west-1.amazonaws.com/auth0-docs-event-stream-action-templates/docs/images/fr-ca/cdy7uua7fh8z/5dwhOyM1HRNwfV3Co4Da2o/cb6d7a9cbf5c43baece40b0d394fc522/Device_Confirmation_-_French.png" alt="null" />
      </Frame>

      L’utilisateur terminera la transaction en se connectant. Cette étape peut comprendre un ou plusieurs des procédés suivant :

      * Authentifier l’utilisateur
      * Redirection de l’utilisateur vers un fournisseur d’identité pour gérer l’authentification
      * Vérification des sessions actives d’authentification unique (SSO)
      * Obtenir le consentement de l’utilisateur pour l’appareil, à moins qu’il n’ait été donné au préalable

      <Frame>
        <img src="https://mintlify.s3.us-west-1.amazonaws.com/auth0-docs-event-stream-action-templates/docs/images/fr-ca/cdy7uua7fh8z/3GqqaNB7sjcAYTQiTnEEsn/15dcb8ab5d7979ad360f9ab96e9a7fa1/Login_screen_-_French.png" alt="null" />
      </Frame>

      Une fois l’authentification et le consentement obtenus, la demande de confirmation s’affiche :

      <Frame>
        <img src="https://mintlify.s3.us-west-1.amazonaws.com/auth0-docs-event-stream-action-templates/docs/images/fr-ca/cdy7uua7fh8z/2TsQpMa8fzifiojuEXLvDo/3335aa9e4e17d63a97b5240884193dd2/Success_message_-_French.png" alt="null" />
      </Frame>

      À ce stade, l’utilisateur s’est authentifié et l’appareil a été autorisé.
    </Section>

    <Section id={sections[6].id} title={sections[6].title} stepNumber="7">
      Une fois que l’utilisateur a autorisé l’application, celle-ci reçoit une réponse HTTP 200 et la charge utile suivante :

      ```
      {
      "access_token": "eyJz93a...k4laUWw",
      "refresh_token": "GEbRxBN...edjnXbL",
      "id_token": "eyJ0XAi...4faeEoQ",
      "token_type": "Bearer",
      "expires_in": 86400
      }
      ```

      <Warning>
        Vous devez valider vos jetons avant de les enregistrer. Pour en savoir plus, consultez **Valider les jetons d’accès** et **Valider les jetons d’ID**.
      </Warning>

      Les jetons d’accès sont utilisés pour appeler le [point de terminaison Get User Info](/docs/api/authentication#get-user-info) de Authentication API (si l’application de votre appareil a demandé la permission `openid`) ou l’API définie par le paramètre `audience`. Si vous appelez votre propre API, votre application doit vérifier le jeton d’accès avant de l’utiliser.

      Les jetons d’ID contiennent des informations sur l’utilisateur qui doivent être [décodées et extraites](/docs/tokens/id-tokens#id-token-payload). Authentication API ne renvoie un `id_token` que si l’application de votre appareil a demandé la permission `openid`.

      Les jetons d’actualisation sont utilisés pour obtenir un nouveau jeton d’accès ou un nouveau jeton d’ID après l’expiration du précédent. Authentication API ne renvoie un `refresh_token` que si le paramètre **Autoriser l’accès hors ligne** est activé pour l’API indiquée par le paramètre `public` et que l’application de votre appareil a demandé la permission `offline_access`.
    </Section>

    <Section id={sections[7].id} title={sections[7].title} stepNumber="8">
      Pour appeler votre API, votre application doit transmettre le jeton d’accès en tant que jeton de porteur dans l’en-tête `Authorization` de votre requête HTTP.

      ```
      curl --request GET \
      --url https://myapi.com/api \
      --header 'authorization: Bearer AUTH0_API_ACCESS_TOKEN' \
      --header 'content-type: application/json'
      ```
    </Section>

    <Section id={sections[8].id} title={sections[8].title} stepNumber="9">
      Pour obtenir un nouveau jeton d’accès pour un utilisateur, l’application de votre appareil peut appeler [le point de terminaison POST /oauth/token](/docs/api/authentication#-post-oauth-token-) de l’API d’authentication avec le paramètre `refresh_token`.

      ```
      curl --request POST \
      --url 'https://{yourDomain}/oauth/token' \
      --header 'content-type: application/x-www-form-urlencoded' \
      --data grant_type=refresh_token \
      --data 'client_id={yourClientId}' \
      --data 'client_secret={yourClientSecret}' \
      --data refresh_token=AUTH0_REFRESH_TOKEN
      ```

      Si la requête a réussi, l’application de votre appareil reçoit une réponse HTTP 200 avec la charge utile suivante :

      ```
      {
      "access_token": "eyJ...MoQ",
      "expires_in": 86400,
      "scope": "openid offline_access",
      "id_token": "eyJ...0NE",
      "token_type": "Bearer"
      }
      ```

      Pour en savoir plus sur les jetons d’actualisation, veuillez consulter [Jetons d’actualisation](https://auth0.com/docs/secure/tokens/refresh-tokens).
    </Section>

    <Section id={sections[9].id} title={sections[9].title} stepNumber="10">
      Les journaux de locataires sont créés pour toutes les interactions qui ont lieu et peuvent être utilisés pour résoudre les problèmes.

      | **Code** | **Nom**                                              | **Description**                         |
      | -------- | ---------------------------------------------------- | --------------------------------------- |
      | `fdeaz`  | Échec de la demande d’autorisation de l’appareil     |                                         |
      | `fdeac`  | Échec de l’activation de l’appareil                  |                                         |
      | `fdecc`  | L’utilisateur a annulé la confirmation de l’appareil |                                         |
      | `fede`   | Échec de l’échange                                   | Code d’appareil contre un jeton d’accès |
      | `sede`   | Échange réussi                                       | code d’appareil contre un jeton d’accès |

      ### Réponses des jetons

      Il est possible de recevoir plusieurs réponses HTTP 4xx différentes pendant que vous attendez que l’utilisateur autorise l’appareil.

      #### Autorisation en attente

      Vous verrez cette erreur pendant que vous attendez que l’utilisateur agisse. Poursuivez l’interrogation en utilisant `interval` suggéré dans l’étape précédente de ce tutoriel.

      ```
      `HTTP 403`
      {
      "error": "authorization_pending",
      "error_description": "..."
      }
      ```

      #### Ralentissement

      L’interrogation est trop rapide. Ralentissez et utilisez l’intervalle suggéré dans l’étape précédente de ce tutoriel. Pour éviter de recevoir cette erreur en raison de la latence du réseau, vous devez commencer à compter chaque intervalle après la réception de la réponse de la dernière demande d’interrogation.

      ```
      `HTTP 429`
      {
      "error": "slow_down",
      "error_description": "..."
      }
      ```

      #### Jeton expiré

      L’utilisateur n’a pas autorisé l’appareil assez rapidement, par conséquent le `device_code` a expiré. Votre application doit avertir l’utilisateur que le flux a expiré et l’inviter à le réinitialiser.

      <Info>
        Le `expired\_token` n’est renvoyé qu’une seule fois. Ensuite, le point de terminaison renvoie l’erreur `invalid\_grant`.
      </Info>

      ```
      `HTTP 403`
      {
      "error": "expired_token",
      "error_description": "..."
      }
      ```

      #### Accès refusé

      Si l’accès est refusé, vous recevez :

      ```
      `HTTP 403`
      {
      "error": "access_denied",
      "error_description": "..."
      }
      ```

      Cela peut se produire pour diverses raisons, notamment :

      * l’utilisateur a refusé d’autoriser l’appareil,
      * le serveur d’autorisation a refusé la transaction.
      * Une Action configurée a refusé l’accès.
    </Section>

    <Section id={sections[10].id} title={sections[10].title} stepNumber="11">
      Consultez les exemples ci-dessous pour savoir comment mettre en œuvre ce flux dans des applications réelles.

      * [Terrain de jeu du flux de l’appareil](https://auth0.github.io/device-flow-playground/)
      * [AppleTV (Swift)](https://github.com/pushpabrol/auth0-device-flow-appletv) : application simple qui montre comment Auth0 peut être utilisé avec le flux d’autorisation d’un appareil AppleTV.
      * [CLI (Node.js)](https://gist.github.com/panva/652c61e7d847e0ed99926c324fa91b36) : exemple de mise en œuvre d’une CLI qui utilise le flux d’autorisation de l’appareil au lieu du flux du code d’autorisation. La principale différence est que votre CLI n’a pas besoin d’héberger un serveur Web et d’écouter sur un port.
    </Section>

    <Section id={sections[11].id} title={sections[11].title} stepNumber="12">
      Pour utiliser le flux d’autorisation de l’appareil, l’application de l’appareil doit :

      * Prendre en charge l’indication du nom du serveur (SNI)
      * Être une Native Application (Application native)
      * Avoir la [Authentication Method](/docs/fr-ca/secure/application-credentials#application-authentication-methods) définie sur **None**
      * Être [OIDC-conformant (conforme à l’OIDC)](/docs/dashboard/reference/settings-application#oauth)
      * Ne pas être créée au moyen de Dynamic Client Registration (Enregistrement dynamique des clients)

      En outre, le flux d’autorisation de l’appareil ne permet pas :

      * Les Social Connections (Connexions via réseau social) qui utilisent les Auth0 developer keys (Clés de développeur Auth0), sauf si vous utilisez l’Universal Login experience (Expérience de connexion universelle)
      * Les paramètres de la chaîne de requête doivent être accessibles à partir d’une page de connexion ou d’actions hébergées.
    </Section>

    ## Étapes suivantes

    Beau travail! Si vous en êtes arrivé là, vous devriez avoir la connexion, la déconnexion et les informations de profil utilisateur actives dans votre application.

    Cela conclut notre tutoriel de démarrage rapide, mais il y a tellement plus à explorer. Pour en savoir plus sur ce que vous pouvez faire avec Auth0, consultez :

    * [Auth0 Dashboard](https://manage.auth0.com/#) : apprenez à configurer et gérer votre locataire et vos applications Auth0
    * [Auth0 Marketplace](https://marketplace.auth0.com/) : découvrez des intégrations que vous pouvez activer pour étendre les fonctionnalités d’Auth0
  </Content>

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

    <SideMenuSectionItem id={sections[1].id}>
      <SignUpForm lang="fr" />
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[2].id}>
      <SignUpForm lang="fr" />
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[3].id}>
      <SignUpForm lang="fr" />
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[4].id}>
      <SignUpForm lang="fr" />
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[5].id}>
      <SignUpForm lang="fr" />
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[6].id}>
      <SignUpForm lang="fr" />
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[7].id}>
      <SignUpForm lang="fr" />
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[8].id}>
      <SignUpForm lang="fr" />
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[9].id}>
      <SignUpForm lang="fr" />
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[10].id}>
      <SignUpForm lang="fr" />
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[11].id}>
      <SignUpForm lang="fr" />
    </SideMenuSectionItem>
  </SideMenu>
</Recipe>
