source: Klonkt/src/config/google.js@ 546f102

main
Last change on this file since 546f102 was 2248cd2, checked in by roboburr <roboburr@…>, 3 months ago

Google login configurable in-app: Admin → Settings card (no .env required)

config/google.js now reads Client ID/Secret from app_settings (env = fallback),
dynamically (no restart needed). Redirect URI derived from PUBLIC_BASE_URL.
New "Google login (listeners)" card shows the redirect URI to register + fields
for Client ID/Secret + a disconnect option. Self-hosters no longer need to
edit .env.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@…>

  • Property mode set to 100644
File size: 2.8 KB
RevLine 
[9e27d64]1// Google OAuth2 voor LUISTERAARS (reageren). Per-instance: de self-hoster zet
[2248cd2]2// z'n EIGEN Google-client. Zo hangt elke site aan z'n eigen Google Cloud project
3// — geen centrale afhankelijkheid, geen gedeelde aansprakelijkheid.
[32cc601]4//
[2248cd2]5// Config-bron (in deze volgorde): app_settings (ingesteld via Beheer → Instellingen),
6// anders de env-vars. Niet ingesteld → geen "Login met Google"-knop; de rest van
7// de site werkt door. Google-login geeft NOOIT beheerrechten.
[32cc601]8//
[2248cd2]9// De redirect-URI wordt afgeleid van PUBLIC_BASE_URL (<base>/auth/google/callback),
10// of expliciet via GOOGLE_REDIRECT_URI. Die exacte URL moet in Google Cloud staan.
[32cc601]11
[2248cd2]12import { getSetting } from '../services/SettingsService.js';
[32cc601]13
[9e27d64]14const AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth';
15const TOKEN_URL = 'https://oauth2.googleapis.com/token';
16const USERINFO_URL = 'https://openidconnect.googleapis.com/v1/userinfo';
[32cc601]17
[2248cd2]18// Dynamisch lezen (UI-wijziging werkt zonder herstart). app_settings wint, env = fallback.
19function clientId() {
20 return getSetting('google_client_id', '') || process.env.GOOGLE_CLIENT_ID || '';
21}
22function clientSecret() {
23 return getSetting('google_client_secret', '') || process.env.GOOGLE_CLIENT_SECRET || '';
24}
25export function redirectUri() {
26 if (process.env.GOOGLE_REDIRECT_URI) return process.env.GOOGLE_REDIRECT_URI;
27 const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, '');
28 return base ? `${base}/auth/google/callback` : '';
29}
30
31export function currentClientId() { return clientId(); } // niet-geheim, voor het formulier
32export function clientSecretSet() { return !!clientSecret(); }
[9e27d64]33export function googleConfigured() {
[2248cd2]34 return !!(clientId() && clientSecret() && redirectUri());
[c80e78b]35}
36
[9e27d64]37export function authorizeUrl(state) {
38 const p = new URLSearchParams({
[2248cd2]39 client_id: clientId(),
40 redirect_uri: redirectUri(),
[9e27d64]41 response_type: 'code',
42 scope: 'openid email profile',
43 state,
44 access_type: 'online',
45 prompt: 'select_account',
46 });
47 return `${AUTH_URL}?${p.toString()}`;
[32cc601]48}
49
[9e27d64]50export async function exchangeCode(code) {
51 const body = new URLSearchParams({
52 code,
[2248cd2]53 client_id: clientId(),
54 client_secret: clientSecret(),
55 redirect_uri: redirectUri(),
[9e27d64]56 grant_type: 'authorization_code',
57 });
58 const r = await fetch(TOKEN_URL, {
59 method: 'POST',
60 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
61 body,
[c80e78b]62 });
[9e27d64]63 if (!r.ok) throw new Error(`Google token-exchange faalde: ${r.status}`);
64 return r.json(); // { access_token, id_token, ... }
[c80e78b]65}
66
[9e27d64]67// Returns { sub, email, email_verified, name, picture }.
68export async function fetchUserinfo(accessToken) {
69 const r = await fetch(USERINFO_URL, { headers: { Authorization: `Bearer ${accessToken}` } });
70 if (!r.ok) throw new Error(`Google userinfo faalde: ${r.status}`);
71 return r.json();
[c80e78b]72}
Note: See TracBrowser for help on using the repository browser.