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

> Ce guide explique comment intégrer Auth0 à une application Flutter à l'aide de la Trousse de développement logiciel (SDK) Auth0 Flutter.

# Ajouter la connexion à votre application 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: "Application par défaut"
      }];
      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="Applications génériques">
                {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)}>
            Vos modifications ont été enregistrées.
          </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"
    }}>
          Créez un{" "}
          <a href="https://auth0.com/signup" target="_blank" rel="noopener noreferrer">
            compte Auth0
          </a>{" "}
          ou{" "}
          <span className="font-semibold text-primary dark:text-white cursor-pointer" onClick={() => console.log("log in")}>
            connectez-vous
          </span>{" "}
          à votre compte existant pour l'intégrer directement à votre propre locataire.
        </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()) {
              processedNode = processedNode.replace(new RegExp(key, "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: "configure-auth0",
  title: "Configurer Auth0"
}, {
  id: "install-the-auth0-flutter-sdk",
  title: "Installer la Trousse de développement logiciel (SDK) Auth0 Flutter"
}, {
  id: "add-login-to-your-application",
  title: "Ajouter la connexion à votre application"
}, {
  id: "add-logout-to-your-application",
  title: "Ajouter la déconnexion à votre application"
}, {
  id: "show-user-profile-information",
  title: "Afficher les informations de profil de l'utilisateur"
}];

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

    <Info>
      La trousse de développement logiciel (SDK) Flutter ne prend actuellement en charge que les applications Flutter exécutées sur les plateformes Android, iOS et Web.
    </Info>

    Ce démarrage rapide suppose que vous avez déjà une application [Flutter](https://flutter.dev/) en cours d'exécution. Si ce n'est pas le cas, consultez les [guides de « démarrage » de Flutter](https://docs.flutter.dev/get-started/install) pour commencer avec une application simple.

    Vous devriez également connaître 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 avez peut‑être créé la vôtre. Vous aurez besoin de certains renseignements au sujet de cette Application pour communiquer avec Auth0. Vous pouvez obtenir ces informations dans la section [Application Settings](https://manage.auth0.com/#/applications) de l’Auth0 Dashboard.

      <Frame>
        <img src="https://mintcdn.com/generaltranslationinc/3E5d0TEwC25OF1Ek/docs/images/cdy7uua7fh8z/6SC7KnyzCyO8cwXQfril1X/c0d6756c28de0ddcbe938307e529d47a/client_settings.png?fit=max&auto=format&n=3E5d0TEwC25OF1Ek&q=85&s=dde658df066c916342ed5d9af59befc4" width="1105" height="673" data-path="docs/images/cdy7uua7fh8z/6SC7KnyzCyO8cwXQfril1X/c0d6756c28de0ddcbe938307e529d47a/client_settings.png" />
      </Frame>

      <Info>
        Lorsque vous utilisez l’Application par défaut avec une Application native ou une Application monopage, assurez-vous de mettre à jour la **Token
        Endpoint Authentication Method** sur `None` et de définir le **Application Type** sur
        `SPA` ou `Native`.
      </Info>

      Vous avez besoin des renseignements suivants :

      * **Domaine**
      * **ID client**

      <Info>
        Si vous téléchargez l’exemple fourni en haut de cette page, ces renseignements seront déjà remplis pour vous.
      </Info>

      ### Configurer les URL de redirection

      Une URL de redirection (callback URL) est une URL de votre application vers laquelle Auth0 redirige l’utilisateur une fois qu’il a été authentifié. L’URL de redirection de votre application doit être ajoutée au champ **URL de redirection autorisées** dans vos [Application
      Settings](https://manage.auth0.com/#/applications). Si ce champ n’est pas défini, les utilisateurs ne pourront pas se connecter à l’application et recevront une 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’option **Allowed Callback URL** sur `http://localhost:3000`.
      </Info>

      ### Configurer les URL de déconnexion

      Une URL de déconnexion est une URL de votre application vers laquelle Auth0 peut retourner après que l’utilisateur a été déconnecté du
      Serveur d’autorisation. Celle-ci est indiqué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éconnexion autorisées** dans vos [Application Settings](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 recevront une 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éconnexion autorisées** est `http://localhost:3000`.
      </Info>

      ### Configurer les origines Web autorisées

      Vous devez ajouter l’URL de votre application au champ **Allowed Web Origins** dans vos [Application Settings](https://manage.auth0.com/#/applications/\{yourClientId}/settings). Si vous n’enregistrez pas l’URL de votre application ici, l’application ne pourra pas actualiser les jetons d’authentification de façon silencieuse et vos utilisateurs seront déconnectés la prochaine fois qu’ils visiteront l’application ou 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 **Allowed Web Origins** sur `http://localhost:3000`.
      </Info>
    </Section>

    <Section id={sections[1].id} title={sections[1].title} stepNumber="2">
      Ajoutez la trousse de développement logiciel (SDK) Auth0 pour Flutter à votre projet :

      ```bash theme={null}
      flutter pub add auth0_flutter
      ```

      Ajoutez la balise \<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">
      [Universal Login](/docs/fr-CA/authenticate/login/auth0-universal-login) est
      le moyen le plus simple de configurer l’authentification dans votre application. Nous recommandons de l’utiliser pour offrir la meilleure expérience, la meilleure
      sécurité et la gamme de fonctionnalités la plus complète.

      Intégrez Auth0 Universal Login à votre application Flutter Web en utilisant la classe `Auth0Web`. Redirigez vos
      utilisateurs vers la page Auth0 Universal Login d’Auth0 à l’aide de `loginWithRedirect()`.

      <Info>
        Vous devrez normalement spécifier le paramètre `redirectUrl` de
        `loginWithRedirect`. Si vous l’omettez, Auth0 utilisera la [route de connexion par défaut](/docs/fr-CA/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 ensuite accéder au jeton d’ID et aux jetons d’accès pour cet utilisateur en appelant `onLoad` au démarrage de l’application et en traitant les informations d’identification qui vous sont fournies :

      ```js theme={null}
      auth0.onLoad().then((final credentials) => setState(() {
      // Gérez ou stockez les informations d'identification ici

      _credentials = credentials;

      }));
      ```

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

        Ajoutez un bouton à votre application qui appelle `loginWithRedirect()` et qui connecte l'utilisateur à votre application.
        Vérifiez que vous êtes redirigé vers Auth0 pour l’authentification, puis de retour vers votre application.

        Vérifiez que vous pouvez accéder à `credentials` à la suite de l’appel de `onLoad` et que
        vous êtes en mesure d’accéder au jeton d’ID et aux jetons d’accès.
      </Note>
    </Section>

    <Section id={sections[3].id} title={sections[3].title} stepNumber="4">
      Pour déconnecter des utilisateurs, redirigez-les vers le point de terminaison de déconnexion Auth0 afin d’effacer leur session de connexion en appelant la Trousse de développement logiciel (SDK) Flutter Auth0 `logout()`. [En savoir plus sur la déconnexion dans Auth0](/docs/fr-CA/authenticate/login/logout).

      <Info>
        Vous souhaiterez normalement spécifier `returnToUrl` lorsque vous appelez `logout`, sinon
        Auth0 [utilisera par défaut la première URL de la liste des URL de déconnexion autorisées](/docs/fr-CA/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, puis de retour. Vous
        ne devriez plus ê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 de l’utilisateur lors du chargement de la page, et peut être consulté
      et stocké en appelant `onLoad` au démarrage de l’application. L’objet renvoyé par `onLoad`
      contient une propriété `user` avec toutes les propriétés du profil de l’utilisateur. Celui-ci est renseigné en interne en
      décodant le jeton ID.

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

        Ouvrez une session et inspectez la propriété `user` dans le résultat renvoyé. Vérifiez les informations de profil de l’utilisateur actuel, comme `email` ou `name`.
      </Note>
    </Section>

    ## Prochaines étapes

    Excellent travail! Si vous êtes rendu jusqu'ici, vous devriez maintenant avoir la connexion, la déconnexion et les informations de profil utilisateur qui fonctionnent dans votre application.<br /><br />

    Ce tutoriel de démarrage rapide est maintenant terminé, mais il reste encore beaucoup à découvrir. Pour en savoir plus sur ce que vous pouvez faire avec Auth0, consultez :

    * [Auth0 Dashboard](https://manage.auth0.com/dashboard/us/dev-s3674bdouue0bd73) - Découvrez comment configurer et gérer votre tenant Auth0 et vos Applications
    * [trousse de développement logiciel (SDK) auth0-flutter](https://www.github.com/auth0/auth0-flutter/) - Découvrez plus en détail la trousse de développement logiciel (SDK) utilisée dans ce tutoriel
    * [Auth0 Marketplace](https://marketplace.auth0.com/) - Découvrez les intégrations que vous pouvez activer pour étendre les fonctionnalités d’Auth0
  </Content>

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

    <SideMenuSectionItem id={sections[1].id}>
      <SignUpForm />
    </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("Se connecter"))
                else
                  Column(
                    children: [
                      ProfileView(user: _credentials!.user),
                      ElevatedButton(
                          onPressed: () async {
                            await auth0.logout(returnToUrl: 'http://localhost:3000');
                          },
                          child: const Text("Se déconnecter"))
                    ],
                  )
              ],
            );
          }
        }
        ```

        ```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 />
    </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("Se connecter"))
                else
                  Column(
                    children: [
                      ProfileView(user: _credentials!.user),
                      ElevatedButton(
                          onPressed: () async {
                            await auth0.logout(returnToUrl: 'http://localhost:3000');
                          },
                          child: const Text("Se déconnecter"))
                    ],
                  )
              ],
            );
          }
        }
        ```

        ```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>
