Passport

Login & Logout

How to implement login and logout functionality with Laravel Passport

Learn how to implement secure login and logout functionality using Laravel Passport with Nuxt Umbu.


Basic Login

The loginWith method provides a simple way to authenticate users with Laravel Passport.

Using the Composable

<template>
  <form @submit.prevent="handleLogin">
    <div>
      <label for="email">Email</label>
      <input 
        id="email" 
        v-model="credentials.email" 
        type="email" 
        required 
      />
    </div>
    
    <div>
      <label for="password">Password</label>
      <input 
        id="password" 
        v-model="credentials.password" 
        type="password" 
        required 
      />
    </div>
    
    <button type="submit" :disabled="loading">
      {{ loading ? 'Signing in...' : 'Sign In' }}
    </button>
  </form>
</template>

<script setup>
const { loginWith } = useAuth()

const credentials = ref({
  email: '',
  password: ''
})

const loading = ref(false)

const handleLogin = async () => {
  try {
    loading.value = true
    await loginWith('client', credentials.value)
    // User is now logged in and redirected
  } catch (error) {
    console.error('Login failed:', error)
    // Handle login error
  } finally {
    loading.value = false
  }
}
</script>

Login Response

When login succeeds, the response contains:

interface AuthResponse {
  token: string        // OAuth2 access token
  expires: string      // Token expiration timestamp
  refresh_token: string // Token for refreshing access
}

Custom Login Endpoint

You can customize the login endpoint in your configuration:

nuxt.config.ts
export default defineNuxtConfig({
  auth: {
    provider: 'passport',
    strategies: {
      client: {
        endpoints: {
          login: {
            url: '/oauth/token',
            method: 'POST',
            alias: 'oauth-token'
          }
        }
      }
    }
  }
})

Basic Logout

The logout method handles session termination and cleanup.

Simple Logout Implementation

<template>
  <div v-if="loggedIn">
    <p>Welcome, {{ user?.name }}!</p>
    <button @click="handleLogout">
      Sign Out
    </button>
  </div>
</template>

<script setup>
const { loggedIn, user, logout } = useAuth()

const handleLogout = async () => {
  try {
    await logout('client')
    // User is now logged out and redirected
  } catch (error) {
    console.error('Logout failed:', error)
    // Handle logout error
  }
}
</script>

Advanced Login with Error Handling

<script setup>
const { loginWith } = useAuth()

const credentials = ref({
  email: '',
  password: ''
})

const error = ref('')
const loading = ref(false)

const handleLogin = async () => {
  error.value = ''
  loading.value = true
  
  try {
    await loginWith('client', credentials.value)
    // Success - user will be redirected automatically
  } catch (err) {
    // Handle different error types
    if (err.statusCode === 401) {
      error.value = 'Invalid credentials'
    } else if (err.statusCode === 422) {
      error.value = 'Validation error'
    } else {
      error.value = 'Login failed. Please try again.'
    }
  } finally {
    loading.value = false
  }
}
</script>

Login with Remember Me

Implement "Remember Me" functionality by extending the credentials:

<script setup>
const credentials = ref({
  email: '',
  password: '',
  remember: false
})

const handleLogin = async () => {
  await loginWith('client', credentials.value)
}
</script>

Note: The remember value must be honored by your backend login endpoint and Laravel Passport/session configuration to change token or session lifetime. This example depends on this existing backend contract - ensure your server is configured to handle the remember parameter appropriately.

Multiple Authentication Strategies

Configure multiple strategies for different user types:

nuxt.config.ts
export default defineNuxtConfig({
  auth: {
    provider: 'passport',
    strategies: {
      admin: {
        endpoints: {
          login: { url: '/api/admin/login', method: 'POST' },
          user: { url: '/api/admin/user', method: 'GET' }
        },
        redirect: {
          login: '/admin/dashboard',
          logout: '/admin/login'
        }
      },
      customer: {
        endpoints: {
          login: { url: '/api/customer/login', method: 'POST' },
          user: { url: '/api/customer/user', method: 'GET' }
        },
        redirect: {
          login: '/customer/dashboard',
          logout: '/customer/login'
        }
      }
    }
  }
})
<script setup>
const { loginWith } = useAuth()

const adminCredentials = ref({
  email: 'admin@example.com',
  password: ''
})

const customerCredentials = ref({
  email: 'customer@example.com',
  password: ''
})

const credentials = ref({
  email: '',
  password: ''
})

// Admin login
const handleAdminLogin = async () => {
  await loginWith('admin', adminCredentials.value)
}

// Customer login
const handleCustomerLogin = async () => {
  await loginWith('customer', customerCredentials.value)
}
</script>

Server-Side Login

For server-side operations, use the server API:

server/api/login.post.ts
export default defineEventHandler(async (event) => {
  const { strategyName, value } = await readBody(event)
  
  try {
    const response = await $fetch('/oauth/token', {
      method: 'POST',
      body: {
        grant_type: 'password',
        client_id: process.env.AUTH_CLIENT_ID,
        client_secret: process.env.AUTH_CLIENT_SECRET,
        username: value.email,
        password: value.password
      }
    })
    
    return response
  } catch (error) {
    throw createError({
      statusCode: 401,
      statusMessage: 'Invalid credentials'
    })
  }
})

Logout with Custom Redirect

<script setup>
const { logout } = useAuth()

const handleLogout = async () => {
  // Override the default redirect
  await logout('client', { redirect: '/custom-goodbye' })
}
</script>

Authentication State

Monitor authentication state changes:

<script setup>
const { loggedIn, user } = useAuth()

// Watch for auth state changes
watch(loggedIn, (isLoggedIn) => {
  if (isLoggedIn) {
    console.log('User logged in:', user.value)
  } else {
    console.log('User logged out')
  }
})
</script>

Error Handling Best Practices

Common Login Errors

ErrorDescriptionSolution
401Invalid credentialsCheck email/password
422Validation errorValidate input format
500Server errorCheck server logs
Network ErrorConnection failedCheck API connectivity

Error Handling Component

<template>
  <div v-if="error" class="error-message">
    {{ error }}
    <button @click="error = ''">×</button>
  </div>
</template>

<script setup>
const error = ref('')

const handleLogin = async () => {
  try {
    await loginWith('client', credentials)
  } catch (err) {
    error.value = getErrorMessage(err)
  }
}

const getErrorMessage = (err) => {
  switch (err.statusCode) {
    case 401: return 'Invalid email or password'
    case 422: return 'Please check your input'
    case 429: return 'Too many attempts. Try again later.'
    default: return 'Login failed. Please try again.'
  }
}
</script>

Next: Learn about Token Management for handling token refresh and expiration.