Passer au contenu principal
Ce Démarrage rapide est actuellement en bêta. Nous aimerions recevoir vos commentaires!
Prérequis : Avant de commencer, assurez-vous d’avoir installé les éléments suivants :
  • Node.js 20 LTS ou plus récent
  • npm 10+ ou yarn 1.22+ ou pnpm 8+
  • jq – requis pour la configuration d’Auth0 CLI
Compatibilité des versions Nuxt : Ce Démarrage rapide fonctionne avec Nuxt 3.x prêt à l’emploi. Pour Nuxt 4.x, assurez-vous d’utiliser Nuxt 4.2+.

Mise en route

Ce démarrage rapide montre comment ajouter l’authentification Auth0 à une application Nuxt.js. Vous allez créer une application monopage sécurisée avec des fonctionnalités de connexion, de déconnexion et de profil utilisateur à l’aide de la trousse de développement logiciel (SDK) Auth0 pour Nuxt.js.
1

Créer un projet

Créez un nouveau projet Nuxt pour ce démarrage rapide
npx nuxi@latest init auth0-nuxt-app
Ouvrez le projet
cd auth0-nuxt-app
2

Installez la trousse de développement logiciel (SDK) Auth0 pour Nuxt

npm add @auth0/auth0-nuxt && npm install
3

Configurez votre application Auth0

Ensuite, vous devez créer une nouvelle application sur votre locataire Auth0 et ajouter les variables d’environnement à votre projet.Vous pouvez choisir de le faire automatiquement en exécutant une commande CLI ou manuellement via le tableau de bord :
Exécutez la commande shell suivante à la racine de votre projet pour créer une application Auth0 et générer un fichier .env :
AUTH0_APP_NAME="My Nuxt App" && brew tap auth0/auth0-cli && brew install auth0 && auth0 login --no-input && auth0 apps create -n "${AUTH0_APP_NAME}" -t regular -c http://localhost:3000/auth/callback -l http://localhost:3000 -o http://localhost:3000 --reveal-secrets --json > auth0-app-details.json && CLIENT_ID=$(jq -r '.client_id' auth0-app-details.json) && CLIENT_SECRET=$(jq -r '.client_secret' auth0-app-details.json) && DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name') && echo "NUXT_AUTH0_DOMAIN=${DOMAIN}" > .env && echo "NUXT_AUTH0_CLIENT_ID=${CLIENT_ID}" >> .env && echo "NUXT_AUTH0_CLIENT_SECRET=${CLIENT_SECRET}" >> .env && echo "NUXT_AUTH0_SESSION_SECRET$(openssl rand -hex 64)" >> .env && echo "NUXT_AUTH0_APP_BASE_URL=http://localhost:3000" >> .env && rm auth0-app-details.json && echo ".env file created with your Auth0 details:" && cat .env
$AppName = "My Nuxt App"; winget install Auth0.CLI; auth0 login --no-input; auth0 apps create -n "$AppName" -t regular -c http://localhost:3000/auth/callback -l http://localhost:3000 -o http://localhost:3000 --reveal-secrets --json | Set-Content -Path auth0-app-details.json; $ClientId = (Get-Content -Raw auth0-app-details.json | ConvertFrom-Json).client_id; $ClientSecret = (Get-Content -Raw auth0-app-details.json | ConvertFrom-Json).client_secret; $Domain = (auth0 tenants list --json | ConvertFrom-Json | Where-Object { $_.active -eq $true }).name; Set-Content -Path .env -Value "NUXT_AUTH0_DOMAIN=$Domain"; Add-Content -Path .env -Value "NUXT_AUTH0_CLIENT_ID=$ClientId"; Add-Content -Path .env -Value "NUXT_AUTH0_CLIENT_SECRET=$ClientSecret"; $SessionSecret = -join ((1..128) | ForEach {'{0:X}' -f (Get-Random -Max 16)}); Add-Content -Path .env -Value "NUXT_AUTH0_SESSION_SECRET=$SessionSecret"; Add-Content -Path .env -Value "NUXT_AUTH0_APP_BASE_URL=http://localhost:3000"; Remove-Item auth0-app-details.json; Write-Output ".env file created with your Auth0 details:"; Get-Content .env
4

Configurer le module Auth0 pour Nuxt

nuxt.config.ts
export default defineNuxtConfig({
  devtools: { enabled: true },
  modules: ['@auth0/auth0-nuxt'],
  runtimeConfig: {
    auth0: {
      domain: process.env.NUXT_AUTH0_DOMAIN,
      clientId: process.env.NUXT_AUTH0_CLIENT_ID,
      clientSecret: process.env.NUXT_AUTH0_CLIENT_SECRET,
      sessionSecret: process.env.NUXT_AUTH0_SESSION_SECRET,
      appBaseUrl: process.env.NUXT_AUTH0_APP_BASE_URL,
    },
  },
})
5

Créer les composants Login, Logout et Profile

Créer des fichiers
mkdir -p app/components && touch app/components/LoginButton.vue && touch app/components/LogoutButton.vue && touch app/components/UserProfile.vue
Et ajoutez les extraits de code suivants
<template>
 <a 
    href="/auth/login" 
    class="button login"
  >
    Se connecter
  </a>
</template>

<style scoped>
.button {
  padding: 1.1rem 2.8rem;
  font-size: 1.2rem;
  font-weight: 600;
  border-radius: 10px;
  border: none;
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  outline: none;
}

.button:focus {
  box-shadow: 0 0 0 4px rgba(99, 179, 237, 0.5);
}

.button.login {
  background-color: #63b3ed;
  color: #1a1e27;
}

.button.login:hover:not(:disabled) {
  background-color: #4299e1;
  transform: translateY(-5px) scale(1.03);
  box-shadow: 0 12px 25px rgba(0, 0, 0, 0.5);
}

.button:disabled {
  opacity: 0.7;
  cursor: not-allowed;
  transform: none;
}
</style>
<template>
 <a
    href="/auth/logout"
    class="button logout"
  >
    Se déconnecter
  </a>
</template>

<style scoped>
.button {
  padding: 1.1rem 2.8rem;
  font-size: 1.2rem;
  font-weight: 600;
  border-radius: 10px;
  border: none;
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  outline: none;
}

.button:focus {
  box-shadow: 0 0 0 4px rgba(99, 179, 237, 0.5);
}

.button.logout {
  background-color: #fc8181;
  color: #1a1e27;
}

.button.logout:hover:not(:disabled) {
  background-color: #e53e3e;
  transform: translateY(-5px) scale(1.03);
  box-shadow: 0 12px 25px rgba(0, 0, 0, 0.5);
}

.button:disabled {
  opacity: 0.7;
  cursor: not-allowed;
  transform: none;
}
</style>
<template>
  <div v-if="pending" class="loading-text">
    Chargement du profil en cours...
  </div>
  <div v-else-if="user" class="profile-container">
    <img 
      :src="user.picture || placeholderImage" 
      :alt="user.name || 'Utilisateur'" 
      class="profile-picture"
      @error="handleImageError"
    />
    <div class="profile-info">
      <div class="profile-name">
        {{ user.name }}
      </div>
      <div class="profile-email">
        {{ user.email }}
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
const user = useUser()
const pending = ref(false)

const placeholderImage = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='50' r='50' fill='%2363b3ed'/%3E%3Cpath d='M50 45c7.5 0 13.64-6.14 13.64-13.64S57.5 17.72 50 17.72s-13.64 6.14-13.64 13.64S42.5 45 50 45zm0 6.82c-9.09 0-27.28 4.56-27.28 13.64v3.41c0 1.88 1.53 3.41 3.41 3.41h47.74c1.88 0 3.41-1.53 3.41-3.41v-3.41c0-9.08-18.19-13.64-27.28-13.64z' fill='%23fff'/%3E%3C/svg%3E`

function handleImageError(e: Event) {
  const target = e.target as HTMLImageElement
  target.src = placeholderImage
}

// Simuler l'état de chargement pour améliorer l'expérience utilisateur
onMounted(() => {
  pending.value = true
  nextTick(() => {
    pending.value = false
  })
})
</script>

<style scoped>
.profile-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}

.profile-picture {
  width: 110px;
  height: 110px;
  border-radius: 50%;
  object-fit: cover;
  border: 3px solid #63b3ed;
  transition: transform 0.3s ease-in-out;
}

.profile-picture:hover {
  transform: scale(1.05);
}

.profile-info {
  text-align: center;
}

.profile-name {
  font-size: 2rem;
  font-weight: 600;
  color: #f7fafc;
  margin-bottom: 0.5rem;
}

.profile-email {
  font-size: 1.15rem;
  color: #a0aec0;
}

.loading-text {
  font-size: 1.8rem;
  font-weight: 500;
  color: #a0aec0;
  animation: pulse 1.5s infinite ease-in-out;
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.6; }
}
</style>
<template>
  <div class="app-container">
    <div class="main-card-wrapper">
      <img 
        src="https://cdn.auth0.com/quantum-assets/dist/latest/logos/auth0/auth0-lockup-en-ondark.png" 
        alt="Logo Auth0" 
        class="auth0-logo"
      />
      <h1 class="main-title">Bienvenue sur Auth0 Nuxt</h1>

      <div v-if="user" class="logged-in-section">
        <div class="logged-in-message">✅ Authentification réussie !</div>
        <h2 class="profile-section-title">Votre profil</h2>
        <div class="profile-card">
          <UserProfile />
        </div>
        <LogoutButton />
      </div>

      <div v-else class="action-card">
        <p class="action-text">Commencez en vous connectant à votre compte</p>
        <LoginButton />
      </div>
    </div>
  </div>
</template>


<script setup lang="ts">
const user = useUser()
</script>

<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');

body {
  margin: 0;
  font-family: 'Inter', sans-serif;
  background-color: #1a1e27;
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  color: #e2e8f0;
  overflow: hidden;
}

.app-container {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  width: 100%;
  padding: 1rem;
  box-sizing: border-box;
}

.loading-state, .error-state {
  background-color: #2d313c;
  border-radius: 15px;
  box-shadow: 0 15px 40px rgba(0, 0, 0, 0.4);
  padding: 3rem;
  text-align: center;
}

.loading-text {
  font-size: 1.8rem;
  font-weight: 500;
  color: #a0aec0;
  animation: pulse 1.5s infinite ease-in-out;
}

.error-state {
  background-color: #c53030;
  color: #fff;
}

.error-title {
  font-size: 2.8rem;
  font-weight: 700;
  margin-bottom: 0.5rem;
}

.error-message {
  font-size: 1.3rem;
  margin-bottom: 0.5rem;
}

.error-sub-message {
  font-size: 1rem;
  opacity: 0.8;
}

.main-card-wrapper {
  background-color: #262a33;
  border-radius: 20px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.05);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2rem;
  padding: 3rem;
  max-width: 500px;
  width: 90%;
  animation: fadeInScale 0.8s ease-out forwards;
}

.auth0-logo {
  width: 160px;
  margin-bottom: 1.5rem;
  opacity: 0;
  animation: slideInDown 1s ease-out forwards 0.2s;
}

.main-title {
  font-size: 2.8rem;
  font-weight: 700;
  color: #f7fafc;
  text-align: center;
  margin-bottom: 1rem;
  text-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
  opacity: 0;
  animation: fadeIn 1s ease-out forwards 0.4s;
}

.action-card {
  background-color: #2d313c;
  border-radius: 15px;
  box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.3), 0 5px 15px rgba(0, 0, 0, 0.3);
  padding: 2.5rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.8rem;
  width: calc(100% - 2rem);
  opacity: 0;
  animation: fadeIn 1s ease-out forwards 0.6s;
}

.action-text {
  font-size: 1.25rem;
  color: #cbd5e0;
  text-align: center;
  line-height: 1.6;
  font-weight: 400;
}

.logged-in-section {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
  width: 100%;
}

.logged-in-message {
  font-size: 1.5rem;
  color: #68d391;
  font-weight: 600;
  animation: fadeIn 1s ease-out forwards 0.8s;
}

.profile-section-title {
  font-size: 2.2rem;
  animation: slideInUp 1s ease-out forwards 1s;
}

.profile-card {
  padding: 2.2rem;
  animation: scaleIn 0.8s ease-out forwards 1.2s;
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes fadeInScale {
  from { opacity: 0; transform: scale(0.95); }
  to { opacity: 1; transform: scale(1); }
}

@keyframes slideInDown {
  from { opacity: 0; transform: translateY(-70px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes slideInUp {
  from { opacity: 0; transform: translateY(50px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.6; }
}

@keyframes scaleIn {
  from { opacity: 0; transform: scale(0.8); }
  to { opacity: 1; transform: scale(1); }
}

@media (max-width: 600px) {
  .main-card-wrapper {
    padding: 2rem;
    margin: 1rem;
  }

  .main-title {
    font-size: 2.2rem;
  }

  .auth0-logo {
    width: 120px;
  }
}
</style>
6

Lancer votre application

npm run dev
Point de contrôleVous devriez maintenant avoir une page de connexion Auth0 entièrement fonctionnelle, accessible à partir de votre localhost.