feat(auth): connexion avec un compte Google (find-or-create, import likes/abos inclus)
- Backend: GET /api/auth/google/{url,callback} (state login distinct du
link import), echange code, profil userinfo, find-or-create (OAuth sub,
puis email), session + cookies comme login interne, connexion stockee
dans oauth_connections pour l'import direct
- Front: bouton 'Se connecter avec Google' sur /auth/login (visible si
configure), page /auth/google/callback (initSession + prefs + redirect
/library/import), cles i18n nav.import deja en place
- Comptes Google-only: password_hash aleatoire (login mot de passe impossible)
This commit is contained in:
+9
-2
@@ -36,9 +36,14 @@ function randomState() {
|
||||
return `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`;
|
||||
}
|
||||
|
||||
export function createOAuthState(userId, provider) {
|
||||
export function createOAuthState(userId, provider, purpose = 'link') {
|
||||
const state = randomState();
|
||||
pendingStates.set(state, { userId: String(userId), provider: String(provider), createdAt: Date.now() });
|
||||
pendingStates.set(state, {
|
||||
userId: userId == null ? null : String(userId),
|
||||
provider: String(provider),
|
||||
purpose: String(purpose || 'link'),
|
||||
createdAt: Date.now(),
|
||||
});
|
||||
// Purge opportuniste.
|
||||
try {
|
||||
const now = Date.now();
|
||||
@@ -233,6 +238,8 @@ export async function fetchGoogleProfile(accessToken) {
|
||||
const data = await getJson('https://www.googleapis.com/oauth2/v2/userinfo', accessToken);
|
||||
return {
|
||||
id: String(data.id || ''),
|
||||
email: String(data.email || ''),
|
||||
verifiedEmail: data.verified_email !== false,
|
||||
displayName: String(data.name || data.email || 'Google'),
|
||||
avatarUrl: String(data.picture || ''),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user