Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs-staging.auth0-mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Get Started

This quickstart demonstrates how to add Auth0 authentication to an Ionic Vue application running on iOS and Android with Capacitor. You’ll build a secure mobile app with login, logout, and user profile features using the Auth0 Vue SDK and Capacitor’s native browser plugins.
1

Create a new project

Create a new Ionic Vue project with Capacitor
npx ionic start auth0-ionic-vue blank --type=vue --capacitor
Open the project
cd auth0-ionic-vue
Make sure you’re using the @ionic/cli package (not the deprecated ionic package). If you see errors about --npm-client during project creation, update your CLI:
npm uninstall -g ionic
npm i -g @ionic/cli
2

Install the Auth0 Vue SDK and Capacitor plugins

npm install @auth0/auth0-vue @capacitor/browser @capacitor/app
@capacitor/browser opens the Auth0 Universal Login page in the device’s system browser (SFSafariViewController on iOS, Chrome Custom Tabs on Android) for secure authentication.@capacitor/app listens for deep link events so your app can handle the OAuth callback when Auth0 redirects back after login.
3

Setup your Auth0 App

Next up, you need to create a new app on your Auth0 tenant. Ionic Capacitor apps use the Native application type with custom URL scheme callbacks.You have three options to set up your Auth0 app: use the Quick Setup tool (recommended), run a CLI command, or configure manually via the Dashboard:
If you used Quick Setup or CLI, go to your app’s Settings tab on the Auth0 Dashboard to configure the callback and logout URLs shown in the Dashboard tab above.
4

Configure the Auth0 Plugin

src/main.ts
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 '../capacitor.config'

// Build the callback URL using your app's package ID
const redirect_uri = `${config.appId}://{yourDomain}/capacitor/${config.appId}/callback`

const app = createApp(App)
  .use(IonicVue)
  .use(router)

app.use(
  createAuth0({
    domain: '{yourDomain}',
    clientId: '{yourClientId}',
    useRefreshTokens: true,
    useRefreshTokensFallback: false,
    authorizationParams: {
      redirect_uri,
    },
  })
)

router.isReady().then(() => {
  app.mount('#app')
})
  • useRefreshTokens: true — Mobile browsers block third-party cookies, so iframe-based silent auth doesn’t work. Refresh tokens call the /oauth/token endpoint directly.
  • useRefreshTokensFallback: false — Prevents the SDK from attempting the iframe-based fallback, which is unavailable on mobile.
  • router.isReady().then(...) — Ensures Vue Router is fully initialized before the SDK processes the OAuth callback, preventing race conditions.
To persist authentication after closing and reopening the application, you may want to set cacheLocation to localstorage, but please be aware of the risks of storing tokens in localstorage. Also, localstorage should be treated as transient in Capacitor apps as the data might be recovered unexpectedly. Please read the guidance on storage in the Capacitor docs.
5

Create Authentication Components

Create component files
mkdir -p src/components && touch src/components/LoginButton.vue && touch src/components/LogoutButton.vue && touch src/components/UserProfile.vue
Add the following code to the new components, and update the existing App.vue and HomePage.vue
6

Run your app

Test in the browser first:
ionic serve
When running in the browser with ionic serve, the custom URL scheme redirect won’t work because browsers cannot handle custom URL schemes. For browser testing, temporarily change redirect_uri to http://localhost:8100 in src/main.ts and add http://localhost:8100 to your Auth0 app’s Allowed Callback URLs and Allowed Logout URLs in the Dashboard. Remember to revert this change before building for native.
To run on a device or simulator, first add the native platforms:
npx cap add ios
npx cap add android
Then build, sync, and run:
ionic build && npx cap sync && npx cap run ios
You must add native platforms with npx cap add before you can run on them. This only needs to be done once per platform. Make sure you’ve registered the custom URL scheme for your platform first.
CheckpointYou should now have a fully functional Auth0 login experience in your Ionic Vue application with login, logout, and user profile information.

Advanced Usage

Register your app’s custom URL scheme so the OS can route the OAuth callback back to your app after authentication.

iOS

Register your custom URL scheme in your ios/App/App/Info.plist:
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>YOUR_PACKAGE_ID</string>
    </array>
  </dict>
</array>
Replace YOUR_PACKAGE_ID with the appId from your capacitor.config.ts. To learn more, read Defining a Custom URL Scheme.

Android

Add an intent filter to your android/app/src/main/AndroidManifest.xml inside the main <activity> tag:
<intent-filter>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data android:scheme="YOUR_PACKAGE_ID" />
</intent-filter>
To learn more, read Create Deep Links to App Content.
After modifying native project files, run npx cap sync to ensure your changes are applied.
Use the built-in authGuard from the Auth0 Vue SDK to protect routes that require authentication:
src/router/index.ts
import { createRouter, createWebHistory } from '@ionic/vue-router'
import { authGuard } from '@auth0/auth0-vue'
import HomePage from '../views/HomePage.vue'
import ProfilePage from '../views/ProfilePage.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: HomePage,
  },
  {
    path: '/profile',
    name: 'Profile',
    component: ProfilePage,
    beforeEnter: authGuard,
  },
]

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes,
})

export default router
The authGuard automatically redirects unauthenticated users to the Auth0 Universal Login page. After logging in, they are returned to the originally requested route.
Configure the audience parameter in your createAuth0 configuration to request access tokens for your API:
src/main.ts
app.use(
  createAuth0({
    domain: '{yourDomain}',
    clientId: '{yourClientId}',
    useRefreshTokens: true,
    useRefreshTokensFallback: false,
    authorizationParams: {
      redirect_uri,
      audience: 'YOUR_API_IDENTIFIER',
    },
  })
)
Then use getAccessTokenSilently in your components to retrieve tokens and make authenticated API calls:
src/components/ApiCall.vue
<template>
  <ion-button @click="callApi" :disabled="loading">
    {{ loading ? 'Calling...' : 'Call Protected API' }}
  </ion-button>
  <pre v-if="response">{{ JSON.stringify(response, null, 2) }}</pre>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { useAuth0 } from '@auth0/auth0-vue'
import { IonButton } from '@ionic/vue'

const { getAccessTokenSilently } = useAuth0()
const response = ref(null)
const loading = ref(false)

const callApi = async () => {
  try {
    loading.value = true
    const token = await getAccessTokenSilently()

    const res = await fetch('https://your-api.com/endpoint', {
      headers: {
        Authorization: `Bearer ${token}`,
      },
    })

    response.value = await res.json()
  } catch (error) {
    console.error('API call failed:', error)
  } finally {
    loading.value = false
  }
}
</script>
The getAccessTokenSilently method retrieves the token from the cache or automatically refreshes it using the refresh token when needed.
If you prefer the explicit defineComponent pattern over <script setup>, here’s how the LoginButton component looks using that approach:
src/components/LoginButton.vue
<template>
  <ion-button @click="login" expand="block">Log in</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'

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>
The defineComponent pattern requires explicitly registering child components and returning values from the setup() function. Both patterns are fully supported by the Auth0 Vue SDK.

Callback URL mismatch error

Solution: Verify that the callback URL in your Auth0 Dashboard matches exactly with the URL constructed in your application. Ensure YOUR_PACKAGE_ID matches the appId field in your capacitor.config.ts.

”PKCE not allowed” error

Fix:
  1. Go to Auth0 Dashboard > Applications > Your Application
  2. Change the Application Type to Native
  3. Set Token Endpoint Authentication Method to None
  4. Save changes and try again

SSO not working on iOS

Capacitor’s Browser plugin uses SFSafariViewController, which does not share cookies with Safari on iOS 11+. If you need SSO, use a compatible plugin that uses ASWebAuthenticationSession.

Login works but user stays unauthenticated after app restart

Enable cacheLocation: 'localstorage' in the createAuth0 configuration to persist tokens across app restarts. Be aware of the security implications. The SDK also supports custom cache implementations for more secure storage.

Browser doesn’t close after login

Ensure you are calling Browser.close() inside the appUrlOpen event listener in your App.vue component. On Android, Browser.close() is a no-op, so the browser closes automatically.

Login page opens in the device’s default browser app

If the login page opens in Safari or Chrome instead of an in-app browser overlay, make sure you’re passing the openUrl callback to loginWithRedirect and logout. Without it, the SDK defaults to window.location.href, which navigates the entire app away.