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

> This guide demonstrates how to integrate Auth0 with an Ionic (Vue) & Capacitor application using the Auth0 Vue SDK

# Add login to your Ionic Vue with Capacitor app

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: "mz9iNEIo2PHu7oeh8QRt19ndTyyCIgai",
      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 = () => {
  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 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>;
};

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: "getting-started",
  title: "Getting started"
}, {
  id: "configure-auth0",
  title: "Configure Auth0"
}, {
  id: "install-the-auth0-vue-sdk",
  title: "Install the Auth0 Vue SDK"
}, {
  id: "configure-the-createauht0-plugin",
  title: "Configure the CreateAuht0 plugin"
}, {
  id: "add-login-to-your-application",
  title: "Add login to your application"
}, {
  id: "handle-the-login-callback",
  title: "Handle the login callback"
}, {
  id: "add-logout-to-your-application",
  title: "Add logout to your application"
}, {
  id: "show-the-user-profile",
  title: "Show the user profile"
}];

<Recipe>
  <Content>
    Auth0 allows you to quickly add authentication and gain access to user profile information in your application.
    This guide demonstrates how to integrate Auth0 with an Ionic (Vue) & Capacitor application using the [Auth0 Vue SDK](https://github.com/auth0/auth0-vue).

    <Section id={sections[0].id} title={sections[0].title} stepNumber="1">
      This quickstart assumes you already have an [Ionic](https://ionicframework.com/) application up and running with [Capacitor](https://capacitorjs.com/). If not, check out the [Using
      Capacitor with Ionic Framework guide](https://capacitorjs.com/docs/getting-started/with-ionic) to get started with a simple app, or clone [our sample
      apps](https://github.com/auth0-samples/auth0-ionic-samples).

      You should also be familiar with the [Capacitor development workflow](https://capacitorjs.com/docs/basics/workflow).
    </Section>

    <Section id={sections[1].id} title={sections[1].title} stepNumber="2">
      To use Auth0 services, you need to have an application set up in the Auth0 Dashboard. The Auth0 application is
      where you will configure how you want authentication to work for your project.

      <Info>
        Throughout this article, `YOUR_PACKAGE_ID` is your application's package ID. This can be
        found and configured in the `appId` field in your `capacitor.config.ts` file. See
        [Capacitor's Config schema](https://capacitorjs.com/docs/config#schema) for more info.
      </Info>

      ### Configure an application

      Use the interactive selector to create a new Auth0 application or select an existing application that represents
      the project you want to integrate with. Every application in Auth0 is assigned an alphanumeric, unique client ID
      that your application code will use to call Auth0 APIs through the SDK.

      Any settings you configure using this quickstart will automatically update for your application in the [Dashboard](https://manage.auth0.com/#/), which is where you
      can manage your applications in the future.

      If you would rather explore a complete configuration, you can view a sample application instead.

      ### Configure Callback URLs

      A callback URL is a URL in your application that you would like Auth0 to redirect users to after they have
      authenticated. If not set, users will not be returned to your application after they log in

      <Info>
        If you are following along with our sample project, set this to
        `YOUR_PACKAGE_ID://{yourDomain}/capacitor/YOUR_PACKAGE_ID/callback`
      </Info>

      ### Configure Logout URLs

      A logout URL is a URL in your application that you would like Auth0 to redirect users to after they have logged
      out. If not set, users will not be able to log out from your application and will receive an error.

      <Info>
        If you are following along with our sample project, set this to
        `YOUR_PACKAGE_ID://{yourDomain}/capacitor/YOUR_PACKAGE_ID/callback`.
      </Info>

      ### Configure Allowed Origins

      To be able to make requests from your native application to Auth0, set the following **Allowed Origins** in
      your [Application Settings](https://manage.auth0.com/#/applications/\{yourClientId}/settings).

      <Info>
        If you are following along with our sample project, set this to
        `capacitor://localhost, http://localhost` for iOS and Android respectively.
      </Info>

      Lastly, be sure that the **Application Type** for your application is set to **Native** in the [Application Settings](https://manage.auth0.com/#/applications/\{yourClientId}/settings).
    </Section>

    <Section id={sections[2].id} title={sections[2].title} stepNumber="3">
      Run the following command within your project directory to install the Auth0 Vue SDK:

      ```bash
      npm install @auth0/auth0-vue
      ```

      The SDK exposes several types that help you integrate Auth0 with your Vue application idiomatically, including a
      module and an authentication service.

      ### Install Capacitor plugins

      This quickstart and sample make use of some of Capacitor's official plugins. Install these into your app using
      the following command:

      npm install @capacitor/browser @capacitor/app

      * [@capacitor/browser](https://capacitorjs.com/docs/apis/browser) - allows you to interact with the device's
        system browser and is used to open the URL to Auth0's authorizaction endpoint
      * [@capacitor/app](https://capacitorjs.com/docs/apis/app) - allows you to subscribe to high-level app
        events, useful for handling callbacks from Auth0

      <Info>
        Capacitor's Browser plugin on iOS uses [SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller), which on iOS 11+ does not share
        cookies with Safari on the device. This means that [SSO](https://auth0.com/docs/sso) will not work on those devices. If you need SSO, please instead use a
        compatible plugin that uses [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession).
      </Info>
    </Section>

    <Section id={sections[3].id} title={sections[3].title} stepNumber="4">
      The SDK exports `createAuth0`, a composable that contains all the services required for the SDK to
      function. This composable should be registered with your application and be configured with your Auth0 domain and
      Client ID.

      The `createAuth0` composable takes the following configuration:

      * `domain`: The `domain`value present under the \*\*Settings \*\*of the application you
        created in the Auth0 Dashboard, or your custom domain if you are using Auth0's [custom domains feature](http://localhost:3000/docs/custom-domains).
      * `clientId`: The Client ID value present under the \*\*Settings \*\*of the application you created
        in the Auth0 Dashboard.
      * `useRefreshTokens`: To use auth0-vue with Ionic on Android and iOS, it's required to enable
        refresh tokens.
      * `useRefreshTokensFallback`: To use auth0-vue with Ionic on Android and iOS, it's required to
        disable the iframe fallback.
      * `authorizationParams.redirect_uri`: The URL to redirect your users after they authenticate with
        Auth0.

      <Info>
        To persist authentication after closing and reopening the application, you may want to set
        `cacheLocation` to `localstorage` when configuring the SDK, but please be aware of
        [the risks of storing tokens in localstorage](https://auth0.com/docs/libraries/auth0-single-page-app-sdk#change-storage-options). Also, localstorage should be treated
        as **transient** in Capacitor app as the data might be recovered unexpectedly in certain
        circumstances. Please read the [guidance on storage in the Capacitor docs](https://capacitorjs.com/docs/guides/storage#why-cant-i-just-use-localstorage-or-indexeddb).

        Additionally, the SDK has the ability to [use a custom cache implementation](https://github.com/auth0/auth0-spa-js/blob/master/EXAMPLES.md#creating-a-custom-cache) to store tokens, if
        you have a requirement to use a more secure and persistent storage mechanism.

        **Note** that we recommend **against** using [Capacitor's Storage plugin](https://capacitorjs.com/docs/apis/storage) to store tokens, as this is
        backed by [UserDefaults](https://developer.apple.com/documentation/foundation/userdefaults) and [SharedPreferences](https://developer.android.com/reference/android/content/SharedPreferences) on iOS and Android respectively. Data stored using
        these APIs is not encrypted, not secure, and could also be synced to the cloud.
      </Info>

      <Note>
        ##### Checkpoint

        Now that you have configured your app with the Auth0 Vue SDK, run your application to verify that the SDK
        is initializing without error, and that your application runs as it did before.
      </Note>
    </Section>

    <Section id={sections[4].id} title={sections[4].title} stepNumber="5">
      In a Capacitor application, the [Capacitor's Browser plugin](https://capacitorjs.com/docs/apis/browser) performs a redirect to the Auth0 [Universal Login Page](https://auth0.com/universal-login). Set the `openUrl`
      parameter on the `loginWithRedirect` function to use `Browser.open` so that the URL is
      opened using the device's system browser component ([SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) on iOS, and [Chrome
      Custom Tabs](https://developer.chrome.com/docs/android/custom-tabs) on Android).

      <Info>
        By default, the SDK's `loginWithRedirect` method uses `window.location.href` to
        navigate to the login page in the default browser application on the user's device rather than the
        system browser component appropriate for the platform. The user would leave your application to
        authenticate and could make for a suboptimal user experience.
      </Info>

      <Note>
        ##### Checkpoint

        The `loginWithRedirect` function tells the SDK to initiate the login flow, using the
        `Browser.open` function to open the login URL with the platform's system browser component by
        setting the `openUrl` parameter. This provides a way for your user to log in to your
        application. Users redirect to the login page at Auth0 and do not receive any errors.
      </Note>
    </Section>

    <Section id={sections[5].id} title={sections[5].title} stepNumber="6">
      Once users logs in with the Universal Login Page, they redirect back to your app via a URL with a custom URL
      scheme. The `appUrlOpen` event must be handled within your app. You can call the
      `handleRedirectCallback` method from the Auth0 SDK to initialize the authentication state.

      You can only use this method on a redirect from Auth0. To verify success, check for the presence of the
      `code` and `state` parameters in the URL.

      The `Browser.close()` method should close the browser when this event is raised.

      <Info>
        This article assumes you will be using Custom URL Schemes to handle the callback within your
        application. To do this, register your `YOUR_PACKAGE_ID` as a URL scheme for your chosen
        platform. To learn more, read [Defining a Custom URL Scheme](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app) for iOS, or [Create Deep Links to App Content](https://developer.android.com/training/app-links/deep-linking) for Android.
      </Info>

      <Note>
        ##### Checkpoint

        Add the `appUrlOpen` to your application's `App` component setup and log in. The
        browser window should close once the user authenticates and logs in to your app.
      </Note>
    </Section>

    <Section id={sections[6].id} title={sections[6].title} stepNumber="7">
      Now that users can log in, you need to configure [a way to log out](https://auth0.com/docs/logout/guides/logout-auth0). Users must redirect to the Auth0 logout endpoint in the browser to clear
      their browser session. Again, Capacitor's Browser plugin should perform this redirect so that the user does not
      leave your app and receive a suboptimal experience.

      To achieve this with Ionic and Capacitor in conjunction with the Auth0 SDK:

      * Construct the URL for your app Auth0 should use to redirect to after logout. This is a URL that uses your
        registered custom scheme and Auth0 domain. Add it to your \*\*Allowed Logout URLs \*\*configuration in the
        Auth0 Dashboard
      * Logout from the SDK by calling `logout`, and pass your redirect URL back as the
        `logoutParams.returnTo`parameter.
      * Set the `openUrl`parameter to a callback that uses the Capacitor browser plugin to open the URL
        using `Browser.open`.

      <Info>
        Similar to the login step, if you do not set `openUrl` when calling `logout`, the
        SDK redirects the user to the logout URL using the default browser application on the device, which
        provides a suboptimal user experience.
      </Info>

      <Note>
        ##### Checkpoint

        Provide a way for your users to log out of your application. Verify that you redirect to Auth0 and then
        to the address you specified in the `returnTo` parameter. Check that you are no longer logged
        in to your application.
      </Note>
    </Section>

    <Section id={sections[7].id} title={sections[7].title} stepNumber="8">
      The Auth0 Vue SDK retrieves the [user's profile](https://auth0.com/docs/users/concepts/overview-user-profile) associated with logged-in users in whatever component you need, such as their
      name or profile picture, to personalize the user interface. The profile information is available through the
      `user` property exposed by the `useAuth0()` composable.

      Initializing the SDK is asynchronous, and you should guard the user profile by checking the
      `isLoading` and `user` properties. Once `isLoading` is `false` and
      `user` has a value, the user profile can be used.

      <Note>
        ##### Checkpoint

        Provide a way for your users to see their user profile details within the app and verify you are able to
        retrieve and see your profile information on screen once you have logged in.
      </Note>
    </Section>

    ## Next Steps

    Excellent work! If you made it this far, you should now have login, logout, and user profile information running in your application.

    This concludes our quickstart tutorial, but there is so much more to explore. To learn more about what you can do with Auth0, check out:

    * [Auth0 Dashboard](https://manage.auth0.com/dashboard/us/dev-gja8kxz4ndtex3rq) - Learn how to configure and manage your Auth0 tenant and applications
    * [Auth0 Marketplace](https://marketplace.auth0.com/) - Discover integrations you can enable to extend Auth0’s functionality
  </Content>

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

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

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

    <SideMenuSectionItem id={sections[3].id}>
      <CodeGroup>
        ```ts main.ts lines highlight={}
        import { createApp } from "vue";
        import App from "./App.vue";
        import router from "./router";

        import { IonicVue } from "@ionic/vue";

        import { createAuth0 } from "@auth0/auth0-vue";
        import config from "./auth.config";

        // ..

        // Build the URL that Auth0 should redirect back to
        const redirect_uri = `${config.appId}://dev-gja8kxz4ndtex3rq.us.auth0.com/capacitor/${config.appId}/callback`;

        const app = createApp(App).use(IonicVue).use(router);

        app.use(
          createAuth0({
            domain: "dev-gja8kxz4ndtex3rq.us.auth0.com",
            clientId: "mz9iNEIo2PHu7oeh8QRt19ndTyyCIgai",
            useRefreshTokens: true,
            useRefreshTokensFallback: false,
            authorizationParams: {
              redirect_uri
            }
          })
        );

        router.isReady().then(() => {
          app.mount("#app");
        });
        ```

        ```html LoginButton.vue lines highlight={}
        <template>
          <ion-button @click="login">Log in</ion-button>
        </template>

        <script lang="ts">
        import { defineComponent } from "vue";
        import { IonApp, IonRouterOutlet } from "@ionic/vue";

        import { useAuth0 } from "@auth0/auth0-vue";
        import { App as CapApp } from "@capacitor/app";
        import { Browser } from "@capacitor/browser";

        export default defineComponent({
          components: {
            IonButton,
          },
          setup() {
            const { loginWithRedirect } = useAuth0();

            const login = async () => {
              await loginWithRedirect({
                openUrl: (url: string) =>
                  Browser.open({
                    url,
                    windowName: "_self",
                  }),
              });
            };

            return { login };
          },
        });
        </script>
        ```

        ```html LogoutButton.vue lines highlight={}
        <template>
          <ion-button @click="onLogout">Log out</ion-button>
        </template>

        <script lang="ts">
        import { defineComponent } from "vue";
        import { useAuth0 } from "@auth0/auth0-vue";
        import { Browser } from "@capacitor/browser";
        import { IonButton } from "@ionic/vue";
        import { callbackUri } from "../auth.config";

        export default defineComponent({
          components: {
            IonButton,
          },
          setup() {
            const { logout } = useAuth0();

            const onLogout = async () => {
              await logout({
                logoutParams: {
                  returnTo: callbackUri,
                },
                openUrl: (url: string) =>
                  Browser.open({
                    url,
                    windowName: "_self",
                  }),
              });
            };

            return {
              onLogout,
            };
          },
        });
        </script>
        ```

        ```html UserProfile.vue lines highlight={}
        <template>
          <div v-if="isLoading">Loading ...</div>
          <div v-else-if="!user"></div>
          <div v-else class="profile-container">
            <ion-avatar>
              <img :src="user.picture" :alt="user.name" />
            </ion-avatar>
            <h2>{{ user.name }}</h2>
            <p>{{ user.email }}</p>
          </div>
        </template>

        <script lang="ts">
        import { defineComponent } from "vue";
        import { useAuth0 } from "@auth0/auth0-vue";
        import { IonAvatar } from "@ionic/vue";

        export default defineComponent({
          components: {
            IonAvatar,
          },
          setup() {
            const { user, isLoading } = useAuth0();

            return { user, isLoading };
          },
        });
        </script>
        ```
      </CodeGroup>
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[4].id}>
      <CodeGroup>
        ```html LoginButton.vue lines highlight={}
        <template>
          <ion-button @click="login">Log in</ion-button>
        </template>

        <script lang="ts">
        import { defineComponent } from "vue";
        import { IonApp, IonRouterOutlet } from "@ionic/vue";

        import { useAuth0 } from "@auth0/auth0-vue";
        import { App as CapApp } from "@capacitor/app";
        import { Browser } from "@capacitor/browser";

        export default defineComponent({
          components: {
            IonButton,
          },
          setup() {
            const { loginWithRedirect } = useAuth0();

            const login = async () => {
              await loginWithRedirect({
                openUrl: (url: string) =>
                  Browser.open({
                    url,
                    windowName: "_self",
                  }),
              });
            };

            return { login };
          },
        });
        </script>
        ```

        ```ts main.ts lines highlight={}
        import { createApp } from "vue";
        import App from "./App.vue";
        import router from "./router";

        import { IonicVue } from "@ionic/vue";

        import { createAuth0 } from "@auth0/auth0-vue";
        import config from "./auth.config";

        // ..

        // Build the URL that Auth0 should redirect back to
        const redirect_uri = `${config.appId}://dev-gja8kxz4ndtex3rq.us.auth0.com/capacitor/${config.appId}/callback`;

        const app = createApp(App).use(IonicVue).use(router);

        app.use(
          createAuth0({
            domain: "dev-gja8kxz4ndtex3rq.us.auth0.com",
            clientId: "mz9iNEIo2PHu7oeh8QRt19ndTyyCIgai",
            useRefreshTokens: true,
            useRefreshTokensFallback: false,
            authorizationParams: {
              redirect_uri
            }
          })
        );

        router.isReady().then(() => {
          app.mount("#app");
        });
        ```

        ```html LogoutButton.vue lines highlight={}
        <template>
          <ion-button @click="onLogout">Log out</ion-button>
        </template>

        <script lang="ts">
        import { defineComponent } from "vue";
        import { useAuth0 } from "@auth0/auth0-vue";
        import { Browser } from "@capacitor/browser";
        import { IonButton } from "@ionic/vue";
        import { callbackUri } from "../auth.config";

        export default defineComponent({
          components: {
            IonButton,
          },
          setup() {
            const { logout } = useAuth0();

            const onLogout = async () => {
              await logout({
                logoutParams: {
                  returnTo: callbackUri,
                },
                openUrl: (url: string) =>
                  Browser.open({
                    url,
                    windowName: "_self",
                  }),
              });
            };

            return {
              onLogout,
            };
          },
        });
        </script>
        ```

        ```html UserProfile.vue lines highlight={}
        <template>
          <div v-if="isLoading">Loading ...</div>
          <div v-else-if="!user"></div>
          <div v-else class="profile-container">
            <ion-avatar>
              <img :src="user.picture" :alt="user.name" />
            </ion-avatar>
            <h2>{{ user.name }}</h2>
            <p>{{ user.email }}</p>
          </div>
        </template>

        <script lang="ts">
        import { defineComponent } from "vue";
        import { useAuth0 } from "@auth0/auth0-vue";
        import { IonAvatar } from "@ionic/vue";

        export default defineComponent({
          components: {
            IonAvatar,
          },
          setup() {
            const { user, isLoading } = useAuth0();

            return { user, isLoading };
          },
        });
        </script>
        ```
      </CodeGroup>
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[5].id}>
      <CodeGroup>
        ```ts main.ts lines highlight={}
        import { createApp } from "vue";
        import App from "./App.vue";
        import router from "./router";

        import { IonicVue } from "@ionic/vue";

        import { createAuth0 } from "@auth0/auth0-vue";
        import config from "./auth.config";

        // ..

        // Build the URL that Auth0 should redirect back to
        const redirect_uri = `${config.appId}://dev-gja8kxz4ndtex3rq.us.auth0.com/capacitor/${config.appId}/callback`;

        const app = createApp(App).use(IonicVue).use(router);

        app.use(
          createAuth0({
            domain: "dev-gja8kxz4ndtex3rq.us.auth0.com",
            clientId: "mz9iNEIo2PHu7oeh8QRt19ndTyyCIgai",
            useRefreshTokens: true,
            useRefreshTokensFallback: false,
            authorizationParams: {
              redirect_uri
            }
          })
        );

        router.isReady().then(() => {
          app.mount("#app");
        });
        ```

        ```html LoginButton.vue lines highlight={}
        <template>
          <ion-button @click="login">Log in</ion-button>
        </template>

        <script lang="ts">
        import { defineComponent } from "vue";
        import { IonApp, IonRouterOutlet } from "@ionic/vue";

        import { useAuth0 } from "@auth0/auth0-vue";
        import { App as CapApp } from "@capacitor/app";
        import { Browser } from "@capacitor/browser";

        export default defineComponent({
          components: {
            IonButton,
          },
          setup() {
            const { loginWithRedirect } = useAuth0();

            const login = async () => {
              await loginWithRedirect({
                openUrl: (url: string) =>
                  Browser.open({
                    url,
                    windowName: "_self",
                  }),
              });
            };

            return { login };
          },
        });
        </script>
        ```

        ```html LogoutButton.vue lines highlight={}
        <template>
          <ion-button @click="onLogout">Log out</ion-button>
        </template>

        <script lang="ts">
        import { defineComponent } from "vue";
        import { useAuth0 } from "@auth0/auth0-vue";
        import { Browser } from "@capacitor/browser";
        import { IonButton } from "@ionic/vue";
        import { callbackUri } from "../auth.config";

        export default defineComponent({
          components: {
            IonButton,
          },
          setup() {
            const { logout } = useAuth0();

            const onLogout = async () => {
              await logout({
                logoutParams: {
                  returnTo: callbackUri,
                },
                openUrl: (url: string) =>
                  Browser.open({
                    url,
                    windowName: "_self",
                  }),
              });
            };

            return {
              onLogout,
            };
          },
        });
        </script>
        ```

        ```html UserProfile.vue lines highlight={}
        <template>
          <div v-if="isLoading">Loading ...</div>
          <div v-else-if="!user"></div>
          <div v-else class="profile-container">
            <ion-avatar>
              <img :src="user.picture" :alt="user.name" />
            </ion-avatar>
            <h2>{{ user.name }}</h2>
            <p>{{ user.email }}</p>
          </div>
        </template>

        <script lang="ts">
        import { defineComponent } from "vue";
        import { useAuth0 } from "@auth0/auth0-vue";
        import { IonAvatar } from "@ionic/vue";

        export default defineComponent({
          components: {
            IonAvatar,
          },
          setup() {
            const { user, isLoading } = useAuth0();

            return { user, isLoading };
          },
        });
        </script>
        ```
      </CodeGroup>
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[6].id}>
      <CodeGroup>
        ```html LogoutButton.vue lines highlight={}
        <template>
          <ion-button @click="onLogout">Log out</ion-button>
        </template>

        <script lang="ts">
        import { defineComponent } from "vue";
        import { useAuth0 } from "@auth0/auth0-vue";
        import { Browser } from "@capacitor/browser";
        import { IonButton } from "@ionic/vue";
        import { callbackUri } from "../auth.config";

        export default defineComponent({
          components: {
            IonButton,
          },
          setup() {
            const { logout } = useAuth0();

            const onLogout = async () => {
              await logout({
                logoutParams: {
                  returnTo: callbackUri,
                },
                openUrl: (url: string) =>
                  Browser.open({
                    url,
                    windowName: "_self",
                  }),
              });
            };

            return {
              onLogout,
            };
          },
        });
        </script>
        ```

        ```ts main.ts lines highlight={}
        import { createApp } from "vue";
        import App from "./App.vue";
        import router from "./router";

        import { IonicVue } from "@ionic/vue";

        import { createAuth0 } from "@auth0/auth0-vue";
        import config from "./auth.config";

        // ..

        // Build the URL that Auth0 should redirect back to
        const redirect_uri = `${config.appId}://dev-gja8kxz4ndtex3rq.us.auth0.com/capacitor/${config.appId}/callback`;

        const app = createApp(App).use(IonicVue).use(router);

        app.use(
          createAuth0({
            domain: "dev-gja8kxz4ndtex3rq.us.auth0.com",
            clientId: "mz9iNEIo2PHu7oeh8QRt19ndTyyCIgai",
            useRefreshTokens: true,
            useRefreshTokensFallback: false,
            authorizationParams: {
              redirect_uri
            }
          })
        );

        router.isReady().then(() => {
          app.mount("#app");
        });
        ```

        ```html LoginButton.vue lines highlight={}
        <template>
          <ion-button @click="login">Log in</ion-button>
        </template>

        <script lang="ts">
        import { defineComponent } from "vue";
        import { IonApp, IonRouterOutlet } from "@ionic/vue";

        import { useAuth0 } from "@auth0/auth0-vue";
        import { App as CapApp } from "@capacitor/app";
        import { Browser } from "@capacitor/browser";

        export default defineComponent({
          components: {
            IonButton,
          },
          setup() {
            const { loginWithRedirect } = useAuth0();

            const login = async () => {
              await loginWithRedirect({
                openUrl: (url: string) =>
                  Browser.open({
                    url,
                    windowName: "_self",
                  }),
              });
            };

            return { login };
          },
        });
        </script>
        ```

        ```html UserProfile.vue lines highlight={}
        <template>
          <div v-if="isLoading">Loading ...</div>
          <div v-else-if="!user"></div>
          <div v-else class="profile-container">
            <ion-avatar>
              <img :src="user.picture" :alt="user.name" />
            </ion-avatar>
            <h2>{{ user.name }}</h2>
            <p>{{ user.email }}</p>
          </div>
        </template>

        <script lang="ts">
        import { defineComponent } from "vue";
        import { useAuth0 } from "@auth0/auth0-vue";
        import { IonAvatar } from "@ionic/vue";

        export default defineComponent({
          components: {
            IonAvatar,
          },
          setup() {
            const { user, isLoading } = useAuth0();

            return { user, isLoading };
          },
        });
        </script>
        ```
      </CodeGroup>
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[7].id}>
      <CodeGroup>
        ```html UserProfile.vue lines highlight={}
        <template>
          <div v-if="isLoading">Loading ...</div>
          <div v-else-if="!user"></div>
          <div v-else class="profile-container">
            <ion-avatar>
              <img :src="user.picture" :alt="user.name" />
            </ion-avatar>
            <h2>{{ user.name }}</h2>
            <p>{{ user.email }}</p>
          </div>
        </template>

        <script lang="ts">
        import { defineComponent } from "vue";
        import { useAuth0 } from "@auth0/auth0-vue";
        import { IonAvatar } from "@ionic/vue";

        export default defineComponent({
          components: {
            IonAvatar,
          },
          setup() {
            const { user, isLoading } = useAuth0();

            return { user, isLoading };
          },
        });
        </script>
        ```

        ```ts main.ts lines highlight={}
        import { createApp } from "vue";
        import App from "./App.vue";
        import router from "./router";

        import { IonicVue } from "@ionic/vue";

        import { createAuth0 } from "@auth0/auth0-vue";
        import config from "./auth.config";

        // ..

        // Build the URL that Auth0 should redirect back to
        const redirect_uri = `${config.appId}://dev-gja8kxz4ndtex3rq.us.auth0.com/capacitor/${config.appId}/callback`;

        const app = createApp(App).use(IonicVue).use(router);

        app.use(
          createAuth0({
            domain: "dev-gja8kxz4ndtex3rq.us.auth0.com",
            clientId: "mz9iNEIo2PHu7oeh8QRt19ndTyyCIgai",
            useRefreshTokens: true,
            useRefreshTokensFallback: false,
            authorizationParams: {
              redirect_uri
            }
          })
        );

        router.isReady().then(() => {
          app.mount("#app");
        });
        ```

        ```html LoginButton.vue lines highlight={}
        <template>
          <ion-button @click="login">Log in</ion-button>
        </template>

        <script lang="ts">
        import { defineComponent } from "vue";
        import { IonApp, IonRouterOutlet } from "@ionic/vue";

        import { useAuth0 } from "@auth0/auth0-vue";
        import { App as CapApp } from "@capacitor/app";
        import { Browser } from "@capacitor/browser";

        export default defineComponent({
          components: {
            IonButton,
          },
          setup() {
            const { loginWithRedirect } = useAuth0();

            const login = async () => {
              await loginWithRedirect({
                openUrl: (url: string) =>
                  Browser.open({
                    url,
                    windowName: "_self",
                  }),
              });
            };

            return { login };
          },
        });
        </script>
        ```

        ```html LogoutButton.vue lines highlight={}
        <template>
          <ion-button @click="onLogout">Log out</ion-button>
        </template>

        <script lang="ts">
        import { defineComponent } from "vue";
        import { useAuth0 } from "@auth0/auth0-vue";
        import { Browser } from "@capacitor/browser";
        import { IonButton } from "@ionic/vue";
        import { callbackUri } from "../auth.config";

        export default defineComponent({
          components: {
            IonButton,
          },
          setup() {
            const { logout } = useAuth0();

            const onLogout = async () => {
              await logout({
                logoutParams: {
                  returnTo: callbackUri,
                },
                openUrl: (url: string) =>
                  Browser.open({
                    url,
                    windowName: "_self",
                  }),
              });
            };

            return {
              onLogout,
            };
          },
        });
        </script>
        ```
      </CodeGroup>
    </SideMenuSectionItem>
  </SideMenu>
</Recipe>
