rubis/apps/api/config/ally.ts
ordinarthur ea539cd1d4
All checks were successful
Build & Deploy Web / build-and-deploy (push) Successful in 55s
Build & Deploy API / build-and-deploy (push) Successful in 1m35s
feat(auth): Google SSO via @adonisjs/ally
Backend
- @adonisjs/ally installé + provider Google configuré (config/ally.ts)
  scopes: userinfo.email + userinfo.profile (non-sensibles, validation
  auto par Google)
- Migration : ajoute google_id (nullable unique) sur users + rend password
  nullable (un user créé via Google n'a pas de mdp en base, il pourra
  l'activer plus tard via "mot de passe oublié")
- AuthGoogleController.redirect : entrée OAuth (le bouton SPA pointe ici)
- AuthGoogleController.callback : matche par google_id puis email,
  crée org+plans+user si nouveau, pose le refresh cookie httpOnly,
  redirige le browser vers le SPA /auth/google/complete?next=...
  (next = / pour user complet, /onboarding/entreprise pour nouveau)
- Routes : GET /api/v1/auth/google/{redirect,callback}
- Env : GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_CALLBACK_URL

Frontend
- Composant GoogleButton réutilisable (full-page redirect, pas fetch —
  OAuth nécessite navigation pour les cookies cross-origin Google)
- AuthDivider "ou" entre SSO et formulaire email/password
- Boutons ajoutés sur /login et /signup
- Route /auth/google/complete : appelle POST /api/v1/auth/refresh (le
  cookie posé par la callback est auto-envoyé), stocke access token +
  user dans authStore, navigue vers `next`. Échec → /login + toast.
- Toast d'erreur sur /login si on revient avec ?google=denied|error|...

K3s
- ConfigMap rubis-api-config : ajout GOOGLE_CALLBACK_URL prod
- Secret rubis-app-secrets : ajout GOOGLE_CLIENT_ID + GOOGLE_CLIENT_SECRET
  (posés via kubectl, pas dans le manifest)

Doc
- .claude/deploy-memory.md mis à jour avec la procédure Google Cloud
  Console (créer OAuth client, redirect URIs, écran de consentement)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 09:24:27 +02:00

37 lines
1.3 KiB
TypeScript

import env from '#start/env'
import { defineConfig, services } from '@adonisjs/ally'
/**
* Configuration des providers OAuth (Ally).
*
* V1 : Google uniquement (cf. CLAUDE.md → Auth). Les autres viendront
* plus tard si pertinent (Microsoft pour les TPE qui utilisent O365 ?).
*
* Le callback URL pointe vers l'API en interne (/api/v1/auth/google/callback).
* En prod, le reverse proxy nginx (rubis-web) achemine /api/* vers ce
* service, donc la même URL fonctionne pour le browser et pour Google.
*/
const allyConfig = defineConfig({
google: services.google({
clientId: env.get('GOOGLE_CLIENT_ID', ''),
clientSecret: env.get('GOOGLE_CLIENT_SECRET', ''),
callbackUrl: env.get(
'GOOGLE_CALLBACK_URL',
'http://localhost:3333/api/v1/auth/google/callback'
),
// Scopes minimaux : on a juste besoin de l'email + nom + photo (avatar
// optionnel V2). Pas de Drive/Calendar : on ne touche pas aux données
// Google de l'utilisateur, on s'en sert juste comme provider d'identité.
scopes: ['userinfo.email', 'userinfo.profile'],
prompt: 'select_account',
}),
})
export default allyConfig
declare module '@adonisjs/ally/types' {
interface SocialProviders extends InferSocialProviders<typeof allyConfig> {}
}
import type { InferSocialProviders } from '@adonisjs/ally/types'