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

# Ajouter une fonctionnalité de connexion à votre application Flutter

> Ce guide explique comment intégrer Auth0 à une application Flutter à l’aide de la trousse SDK Auth0 Flutter.

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 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 sections = [{
  id: "configuration-d-auth0",
  title: "Configuration d’Auth0"
}, {
  id: "installer-la-trousse-sdk-flutter-auth0",
  title: "Installer la trousse SDK Flutter Auth0"
}, {
  id: "ajouter-une-fonctionnalité-de-connexion-à-votre-application",
  title: "Ajouter une fonctionnalité de connexion à votre application"
}, {
  id: "ajouter-une-fonctionnalité-de-déconnexion-à-votre-application",
  title: "Ajouter une fonctionnalité de déconnexion à votre application"
}, {
  id: "afficher-les-informations-du-profil-utilisateur",
  title: "Afficher les informations du profil utilisateur"
}];

<Recipe>
  <Content>
    Auth0 vous permet d’ajouter rapidement l’authentification et d’accéder aux informations relatives au profil de l’utilisateur dans votre application. Ce guide explique comment intégrer Auth0 à une application Flutter à l’aide de la trousse [SDK Auth0 Flutter](https://github.com/auth0/auth0-flutter).

    <Info>
      La trousse SDK Flutter ne prend actuellement en charge que les applications Flutter s’exécutant sur les plateformes Android, iOS ou Web.
    </Info>

    Ce guide rapide suppose que vous avez déjà une application [Flutter](https://flutter.dev/) installée et active. Si ce n’est pas le cas, consultez les [guides de démarrage de Flutter](https://docs.flutter.dev/get-started/install) pour commencer l’utilisation d’une application simple.

    Vous devez également être familiarisé avec l’[outil de ligne de commande Flutter](https://docs.flutter.dev/reference/flutter-cli).

    <Section id={sections[0].id} title={sections[0].title} stepNumber="1">
      Lorsque vous vous êtes inscrit à Auth0, une nouvelle application a été créée pour vous, ou vous auriez pu en créer une nouvelle. Vous aurez besoin de quelques informations à propos de cette application pour communiquer avec Auth0. Vous pouvez obtenir ces informations dans la section [Paramètres d’application](https://manage.auth0.com/#/applications) d’Auth0 Dashboard.

      <Frame>
        <img src="https://mintcdn.com/docs-dev-docs-event-stream-action-templates/1giWs3MwX5Akld9c/docs/images/fr-ca/cdy7uua7fh8z/6SC7KnyzCyO8cwXQfril1X/7f204d6b4eb87562043e7f1083aca651/My_App_-_Settings_-_French.png?fit=max&auto=format&n=1giWs3MwX5Akld9c&q=85&s=89026b4a1c2850790129629be7ccb548" alt="null" width="1132" height="756" data-path="docs/images/fr-ca/cdy7uua7fh8z/6SC7KnyzCyO8cwXQfril1X/7f204d6b4eb87562043e7f1083aca651/My_App_-_Settings_-_French.png" />
      </Frame>

      <Info>
        Si vous utilisez l’application par défaut avec une application native ou une application à page unique, veillez à mettre à jour la **méthode d’authentification du point de terminaison des jetons** en la réglant sur `None` et à définir le **type d’application** sur `SPA` ou `Native`.
      </Info>

      Les informations suivantes sont nécessaires :

      * **Domaine**
      * **Identifiant client**

      <Info>
        Si vous téléchargez l’exemple en haut de cette page, les détails sont renseignés pour vous.
      </Info>

      ### Configuration des URL de rappel

      Une URL de rappel est une URL intégrée dans votre application vers laquelle Auth0 redirige l’utilisateur après qu’il s’est authentifié. L’URL de rappel de votre application doit être ajoutée au champ **URL de rappel autorisées** dans les [Paramètres d’application](https://manage.auth0.com/#/applications). Si ce champ n’est pas défini, les utilisateurs ne pourront pas se connecter à l’application et obtiendront un message d’erreur.

      <Info>
        Si vous suivez l’exemple de projet que vous avez téléchargé en haut de cette page, vous devez définir l’**URL de rappel autorisée** sur `http://localhost:3000`.
      </Info>

      ### Configuration des URL de déconnexion

      Une URL de déconnexion est une URL intégrée dans votre application vers laquelle Auth0 peut se rediriger une fois que l’utilisateur a été déconnecté du serveur d’autorisations. Cette URL est spécifiée dans le paramètre de requête `returnTo`. L’URL de déconnexion de votre application doit être ajoutée au champ **URL de déconnexions autorisées** dans les [Application Settings (Paramètres d’application)](https://manage.auth0.com/#/applications). Si ce champ n’est pas défini, les utilisateurs ne pourront pas se déconnecter de l’application et obtiendront un message d’erreur.

      <Info>
        Si vous suivez l’exemple de projet que vous avez téléchargé en haut de cette page, l’URL de déconnexion que vous devez ajouter au champ **URL de déconnexions autorisées** est `http://localhost:3000`.
      </Info>

      ### Configurer les origines Web autorisées

      Vous devez ajouter l’URL de votre application au champ **Origines Web autorisées** dans vos [Application Settings (Paramètres d’application)](https://manage.auth0.com/#/applications/%7ByourClientId%7D/settings). Si vous n’enregistrez pas l’URL de votre application ici, l’application ne pourra pas actualiser silencieusement les jetons d’authentification et vos utilisateurs seront déconnectés la prochaine fois qu’ils visiteront l’application ou qu’ils actualiseront la page.

      <Info>
        Si vous suivez l’exemple de projet que vous avez téléchargé en haut de cette page, vous devez définir l’option **Origines Web autorisées** sur `http://localhost:3000`.
      </Info>
    </Section>

    <Section id={sections[1].id} title={sections[1].title} stepNumber="2">
      Ajoutez la trousse SDK Flutter Auth0 au projet :

      ```
      flutter pub add auth0_flutter
      ```

      Ajoutez l’étiquette de script suivante à votre page `index.html` :

      ```html theme={null}
      <script src="https://cdn.auth0.com/js/auth0-spa-js/2.0/auth0-spa-js.production.js" defer></script>
      ```
    </Section>

    <Section id={sections[2].id} title={sections[2].title} stepNumber="3">
      La [connexion universelle](https://auth0.com/docs/authenticate/login/auth0-universal-login) est le moyen le plus simple de mettre en place l’authentification dans votre application. Nous recommandons de l’utiliser pour une meilleure expérience, une meilleure sécurité et un plus grand nombre de fonctionnalités.

      Intégrez la connexion universelle Auth0 dans votre application Flutter (Web) en utilisant la classe `Auth0Web`. Redirigez vos utilisateurs vers la page de connexion universelle Auth0 en utilisant `loginWithRedirect()`.

      <Info>
        Vous devrez normalement définir le paramètre `redirectUrl` sur `loginWithRedirect`. Si ce paramètre n’est pas spécifié, Auth0 utilisera la [route de connexion par défaut](https://auth0.com/docs/authenticate/login/auth0-universal-login/configure-default-login-routes), qui n’est pas configurée par défaut.
      </Info>

      Lorsqu’un utilisateur se connecte, il est redirigé vers votre application. Vous pouvez alors accéder à l’identificateur et aux jetons d’accès de cet utilisateur en appelant `onLoad` lors du démarrage et en gérant les informations d’identification qui vous sont communiquées :

      ```
      auth0.onLoad().then((final credentials) => setState(() {
      // Handle or store credentials here

      _credentials = credentials;

      }));
      ```

      <Note>
        ##### Point de contrôle

        Ajoutez un bouton à votre application qui appelle `loginWithRedirect()` et déconnecte l’utilisateur de votre application. Vérifiez que vous êtes redirigé vers Auth0 pour l’authentification, puis renvoyé vers votre application.
        Vérifiez que vous pouvez accéder aux `credentials` après avoir appelé `onLoad` et que vous pouvez accéder à l’identifiant et aux jetons d’accès.
      </Note>
    </Section>

    <Section id={sections[3].id} title={sections[3].title} stepNumber="4">
      Pour déconnecter les utilisateurs, redirigez-les vers le point de terminaison Auth0 pour effacer leur session de connexion en appelant la trousse SDK Flutter Auth0 `logout()`. [En savoir plus sur la déconnexion d’Auth0](https://auth0.com/docs/authenticate/login/logout).

      <Info>
        Vous devez normalement spécifier `returnToUrl` lorsque vous appelez `logout`, sinon Auth0 [utilisera par défaut la première URL de la liste URL de déconnexion autorisées](https://auth0.com/docs/authenticate/login/logout/redirect-users-after-logout).
      </Info>

      <Note>
        ##### Point de contrôle

        Ajoutez un bouton à votre application qui appelle `logout()` et déconnecte l’utilisateur de votre application. Lorsque vous le sélectionnez, vérifiez que votre application Flutter vous redirige vers le point de terminaison de déconnexion et vice-versa. Vous ne devriez pas être connecté à votre application.
      </Note>
    </Section>

    <Section id={sections[4].id} title={sections[4].title} stepNumber="5">
      Le profil utilisateur récupère automatiquement les propriétés du profil utilisateur lors du chargement de la page. Il est possible d’y accéder et de les stocker en appelant `onLoad` lors du démarrage de l’application. L’objet retourné à partir de `onLoad` contient une propriété `user` avec toutes les propriétés du profil utilisateur. Cette propriété est alimentée en interne par le décodage du jeton d’ID.

      <Note>
        ##### Point de contrôle

        Connectez-vous et inspectez la propriété `user` par rapport au résultat. Vérifiez les informations de profil utilisateur actuel, telles que son `email` ou `name`.
      </Note>
    </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
    * [Trousse SDK auth0-flutter](https://www.github.com/auth0/auth0-flutter/) : explorez en détail la trousse SDK utilisée dans ce tutoriel
    * [Auth0 Marketplace](https://marketplace.auth0.com/) : découvrez des intégrations que vous pouvez activer pour étendre les fonctionnalités d’Auth0
    * [Configure other identity providers](/docs/identityproviders)
    * [Enable multifactor authentication](/docs/multifactor-authentication)
    * [Learn about attack protection](/docs/attack-protection)
    * [Learn about Actions](/docs/fr-ca/customize/actions)
  </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}>
      <AuthCodeGroup>
        ```dart main_view.dart lines theme={null}
        import 'package:auth0_flutter/auth0_flutter.dart';
        import 'package:auth0_flutter/auth0_flutter_web.dart';
        import 'package:flutter/material.dart';
        import 'profile_view.dart';

        class MainView extends StatefulWidget {
          const MainView({Key? key}) : super(key: key);

          @override
          State<MainView> createState() => _MainViewState();
        }

        class _MainViewState extends State<MainView> {
          Credentials? _credentials;

          late Auth0Web auth0;

          @override
          void initState() {
            super.initState();
            auth0 = Auth0Web('dev-s3674bdouue0bd73.us.auth0.com', 'QqpqsvIQHjLodaUIPpabJcIHoG41tbAv');

            auth0.onLoad().then((final credentials) => setState(() {
                _credentials = credentials;
              }));
          }

          @override
          Widget build(BuildContext context) {
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                if (_credentials == null)
                  ElevatedButton(
                      onPressed: () => auth0.loginWithRedirect(redirectUrl: 'http://localhost:3000'),
                      child: const Text("Log in"))
                else
                  Column(
                    children: [
                      ProfileView(user: _credentials!.user),
                      ElevatedButton(
                          onPressed: () async {
                            await auth0.logout(returnToUrl: 'http://localhost:3000');
                          },
                          child: const Text("Log out"))
                    ],
                  )
              ],
            );
          }
        }
        ```

        ```dart profile_view.dart lines theme={null}
        import 'package:auth0_flutter/auth0_flutter.dart';
        import 'package:flutter/material.dart';

        class ProfileView extends StatelessWidget {
          const ProfileView({Key? key, required this.user}) : super(key: key);

          final UserProfile user;

          @override
          Widget build(BuildContext context) {
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                if (user.name != null) Text(user.name!),
                if (user.email != null) Text(user.email!)
              ],
            );
          }
        }
        ```
      </AuthCodeGroup>
    </SideMenuSectionItem>

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

    <SideMenuSectionItem id={sections[4].id}>
      <AuthCodeGroup>
        ```dart main_view.dart lines theme={null}
        import 'package:auth0_flutter/auth0_flutter.dart';
        import 'package:auth0_flutter/auth0_flutter_web.dart';
        import 'package:flutter/material.dart';
        import 'profile_view.dart';

        class MainView extends StatefulWidget {
          const MainView({Key? key}) : super(key: key);

          @override
          State<MainView> createState() => _MainViewState();
        }

        class _MainViewState extends State<MainView> {
          Credentials? _credentials;

          late Auth0Web auth0;

          @override
          void initState() {
            super.initState();
            auth0 = Auth0Web('dev-s3674bdouue0bd73.us.auth0.com', 'QqpqsvIQHjLodaUIPpabJcIHoG41tbAv');

            auth0.onLoad().then((final credentials) => setState(() {
                _credentials = credentials;
              }));
          }

          @override
          Widget build(BuildContext context) {
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                if (_credentials == null)
                  ElevatedButton(
                      onPressed: () => auth0.loginWithRedirect(redirectUrl: 'http://localhost:3000'),
                      child: const Text("Log in"))
                else
                  Column(
                    children: [
                      ProfileView(user: _credentials!.user),
                      ElevatedButton(
                          onPressed: () async {
                            await auth0.logout(returnToUrl: 'http://localhost:3000');
                          },
                          child: const Text("Log out"))
                    ],
                  )
              ],
            );
          }
        }
        ```

        ```dart profile_view.dart lines theme={null}
        import 'package:auth0_flutter/auth0_flutter.dart';
        import 'package:flutter/material.dart';

        class ProfileView extends StatelessWidget {
          const ProfileView({Key? key, required this.user}) : super(key: key);

          final UserProfile user;

          @override
          Widget build(BuildContext context) {
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                if (user.name != null) Text(user.name!),
                if (user.email != null) Text(user.email!)
              ],
            );
          }
        }
        ```
      </AuthCodeGroup>
    </SideMenuSectionItem>
  </SideMenu>
</Recipe>
