Add authentication to your Vue.js app
This guide walks you through adding authentication and access control to a Vue.js application using the @lumoauth/sdk with Vue Composition API.
Before you start
You need:
- A LumoAuth account with a configured tenant (sign up)
- A registered OAuth application with a redirect URI (e.g.,
http://localhost:5173/auth/callback) - Vue 3 + Vite
Install the SDK
npm install @lumoauth/sdk
Environment variables
VITE_LUMOAUTH_DOMAIN=https://app.lumoauth.dev
VITE_LUMOAUTH_TENANT=YOUR_TENANT_SLUG
VITE_LUMOAUTH_CLIENT_ID=YOUR_CLIENT_ID
Set up the composable
Create src/composables/useLumoAuth.ts:
import { inject, provide, type InjectionKey } from 'vue';
import { LumoAuth, AuthModule } from '@lumoauth/sdk';
const LumoAuthKey: InjectionKey<LumoAuth> = Symbol('LumoAuth');
const AuthModuleKey: InjectionKey<AuthModule> = Symbol('AuthModule');
export function provideLumoAuth() {
const domain = import.meta.env.VITE_LUMOAUTH_DOMAIN as string;
const tenantSlug = import.meta.env.VITE_LUMOAUTH_TENANT as string;
const clientId = import.meta.env.VITE_LUMOAUTH_CLIENT_ID as string;
const authModule = new AuthModule({ baseUrl: domain, tenantSlug, clientId });
const client = new LumoAuth({
baseUrl: domain,
tenantSlug,
clientId,
token: () => sessionStorage.getItem('lumoauth_access_token') || '',
});
provide(LumoAuthKey, client);
provide(AuthModuleKey, authModule);
return { client, authModule };
}
export function useLumoAuth() {
const client = inject(LumoAuthKey);
if (!client) throw new Error('Call provideLumoAuth() in a parent component');
return client;
}
export function useAuthModule() {
const auth = inject(AuthModuleKey);
if (!auth) throw new Error('Call provideLumoAuth() in a parent component');
return auth;
}
Call provideLumoAuth() in App.vue:
<script setup lang="ts">
import { provideLumoAuth } from './composables/useLumoAuth';
provideLumoAuth();
</script>
PKCE sign-in
import { useAuthModule } from './composables/useLumoAuth';
const auth = useAuthModule();
async function signIn() {
const redirectUri = `${window.location.origin}/auth/callback`;
const { url, codeVerifier, state } = await auth.buildAuthorizationUrl({ redirectUri });
sessionStorage.setItem('lumoauth_pkce_verifier', codeVerifier);
sessionStorage.setItem('lumoauth_pkce_state', state);
window.location.href = url;
}
Callback handler
Mount this component at /auth/callback:
<script setup lang="ts">
import { onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { useAuthModule } from '../composables/useLumoAuth';
const router = useRouter();
const auth = useAuthModule();
onMounted(async () => {
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
const returnedState = params.get('state');
const codeVerifier = sessionStorage.getItem('lumoauth_pkce_verifier');
const savedState = sessionStorage.getItem('lumoauth_pkce_state');
if (!code || returnedState !== savedState || !codeVerifier) {
router.push('/');
return;
}
const tokens = await auth.exchangeCodeForTokens({
code,
codeVerifier,
redirectUri: `${window.location.origin}/auth/callback`,
});
sessionStorage.setItem('lumoauth_access_token', tokens.access_token);
sessionStorage.removeItem('lumoauth_pkce_verifier');
sessionStorage.removeItem('lumoauth_pkce_state');
router.push('/dashboard');
});
</script>
<template><p>Signing in…</p></template>
Permission checks
import { ref, onMounted } from 'vue';
import { useLumoAuth } from '../composables/useLumoAuth';
const client = useLumoAuth();
const canEdit = ref(false);
onMounted(async () => {
canEdit.value = await client.permissions.check('documents.edit');
});