Skip to main content

Documentation Index

Fetch the complete documentation index at: https://auth0-feat-ionic-capacitor-quickstart-modernization.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
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

ionic serve
If port 8100 is in use, run: ionic serve --port 8101 and update your Auth0 app’s callback URLs accordingly.To test on a device or emulator, run ionic cap run ios or ionic cap run android. 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.