Passport
Token Management
Managing OAuth2 tokens, refresh, and expiration with Laravel Passport
Learn how to manage OAuth2 tokens, handle automatic refresh, and deal with token expiration in Laravel Passport.
Token Overview
Laravel Passport uses OAuth2 tokens for authentication. Nuxt Umbu handles token management automatically, including:
- Access tokens - Short-lived tokens for API requests
- Refresh tokens - Long-lived tokens for obtaining new access tokens
- Token expiration - Automatic detection and refresh
- Secure storage - HTTP-only cookies and localStorage fallback
Token Storage
Server-Side (SSR)
Tokens are stored in secure HTTP-only cookies:
// Automatic cookie management
const tokenCookie = `${prefix}_token.${strategyName}`
const refreshCookie = `${prefix}_refresh.${strategyName}`
const expirationCookie = `${prefix}_token_expiration.${strategyName}`
Client-Side
Tokens fall back to localStorage for SPA mode:
// Client-side storage
localStorage.setItem(`${prefix}_token.${strategyName}`, token)
localStorage.setItem(`${prefix}_refresh.${strategyName}`, refreshToken)
localStorage.setItem(`${prefix}_token_expiration.${strategyName}`, expires)
Automatic Token Refresh
Nuxt Umbu automatically refreshes tokens when they're about to expire.
Configuration
nuxt.config.ts
export default defineNuxtConfig({
auth: {
provider: 'passport',
strategies: {
client: {
endpoints: {
refresh: {
url: '/oauth/token/refresh',
method: 'POST',
alias: 'token-refresh'
}
}
}
}
}
})
Manual Token Refresh
<script setup>
const { fetchProfile } = useAuth()
const refreshToken = async () => {
try {
await fetchProfile('client')
// Token automatically refreshed if needed
} catch (error) {
console.error('Token refresh failed:', error)
// Handle refresh failure (e.g., redirect to login)
}
}
</script>
Token Expiration Handling
Check Token Status
<script setup>
const { loggedIn, user } = useAuth()
const isTokenExpired = computed(() => {
if (!loggedIn.value) return true
const expiration = localStorage.getItem('__Secure-_token_expiration.client')
return expiration ? Date.now() > parseInt(expiration) : false
})
// Watch for token expiration
watch(isTokenExpired, (expired) => {
if (expired && loggedIn.value) {
console.log('Token expired, need to re-authenticate')
// Redirect to login or refresh token
}
})
</script>
Token Expiration Event
<script setup>
const { fetchProfile } = useAuth()
onMounted(async () => {
try {
await fetchProfile('client')
// This will automatically refresh expired tokens
} catch (error) {
// Token is invalid, redirect to login
await navigateTo('/login')
}
})
</script>
Custom Token Logic
Token Interceptor
plugins/auth-interceptor.client.ts
export default defineNuxtPlugin(() => {
const { $fetch: originalFetch } = useNuxtApp()
const { fetchProfile } = useAuth()
// Intercept API calls to check token validity
const interceptedFetch = async (url, options) => {
try {
return await originalFetch(url, options)
} catch (error) {
if (error.statusCode === 401) {
// Try to refresh token
try {
await fetchProfile('client')
return await originalFetch(url, options)
} catch (refreshError) {
// Refresh failed, redirect to login
await navigateTo('/login')
}
}
throw error
}
}
return {
provide: {
$fetch: interceptedFetch
}
}
})
Token Validation Middleware
middleware/auth.ts
export default defineNuxtRouteMiddleware(async (to) => {
const { loggedIn, fetchProfile } = useAuth()
if (!loggedIn.value) {
return navigateTo('/login')
}
try {
await fetchProfile('client')
// Token is valid
} catch (error) {
// Token is invalid, redirect to login
return navigateTo('/login')
}
})
Advanced Token Management
Multiple Token Strategies
nuxt.config.ts
export default defineNuxtConfig({
auth: {
provider: 'passport',
strategies: {
admin: {
endpoints: {
refresh: { url: '/api/admin/refresh', method: 'POST' }
}
},
api: {
endpoints: {
refresh: { url: '/api/refresh', method: 'POST' }
}
}
}
}
})
Token Refresh with Custom Logic
<script setup>
const { fetchProfile } = useAuth()
const customTokenRefresh = async (strategyName: string) => {
try {
// Custom refresh logic
const response = await $fetch('/custom-refresh', {
method: 'POST',
body: { strategy: strategyName }
})
// Update token storage manually
if (response.token) {
const prefix = '__Secure-'
localStorage.setItem(`${prefix}_token.${strategyName}`, response.token)
localStorage.setItem(`${prefix}_token_expiration.${strategyName}`, response.expires)
}
return response
} catch (error) {
console.error('Custom refresh failed:', error)
throw error
}
}
</script>
Token Security Best Practices
Secure Token Transmission
// Tokens are automatically included in headers
const { headers } = useAuth()
// Manual API call with auth headers
const apiCall = await $fetch('/api/protected', {
headers: {
// Authorization header is automatically added
...headers
}
})
Token Cleanup on Logout
<script setup>
const { logout } = useAuth()
const handleLogout = async () => {
try {
await logout('client')
// All tokens automatically cleared:
// - Access token
// - Refresh token
// - Expiration timestamps
// - 2FA tokens
} catch (error) {
console.error('Logout error:', error)
}
}
</script>
Token Storage Security
nuxt.config.ts
export default defineNuxtConfig({
auth: {
cookie: {
prefix: '__Secure-', // Secure prefix
options: {
httpOnly: true, // Prevent XSS
secure: true, // HTTPS only
sameSite: 'lax', // CSRF protection
priority: 'high' // Cookie priority
}
}
}
})
Debugging Token Issues
Token Inspector
<template>
<div class="token-debug">
<h3>Token Status</h3>
<p>Logged In: {{ loggedIn }}</p>
<p>Strategy: {{ strategy }}</p>
<p>Token Present: !!token</p>
<p>Expires: {{ tokenExpiration }}</p>
<p>Is Expired: isTokenExpired</p>
</div>
</template>
<script setup>
const { loggedIn, strategy, token, tokenExpiration } = useAuth()
const isTokenExpired = computed(() => {
if (!tokenExpiration.value) return true
return Date.now() > parseInt(tokenExpiration.value)
})
</script>
Common Token Issues
| Issue | Cause | Solution |
|---|---|---|
| Token not found | User not logged in | Redirect to login |
| Token expired | Token reached expiration | Refresh token or re-authenticate |
| Invalid token | Token revoked or corrupted | Clear storage and re-authenticate |
| Refresh failed | Refresh token expired | Force logout and re-authenticate |
Next: Learn about Two-Factor Authentication for enhanced security.