source: Klonkt/src/config/google.js@ 09ee2bd

main
Last change on this file since 09ee2bd was 834bcc3, checked in by Robin Genis <roboburr@…>, 3 months ago

i18n: translate Dutch code comments to English across src/

Comments in routes/services/views/config/middleware/assets translated to
English for the public repo. A few dev-facing throw/console message strings
were Englished too. No user-facing UI strings or i18n dictionary values changed
(src/services/i18n.js untouched). Logic unchanged.

Co-Authored-By: Claude <noreply@…>

  • Property mode set to 100644
File size: 2.8 KB
Line 
1// Google OAuth2 for LISTENERS (commenting). Per-instance: each self-hoster sets
2// their OWN Google client. This way every site is tied to its own Google Cloud
3// project — no central dependency, no shared liability.
4//
5// Config source (in this order): app_settings (set via Admin → Settings),
6// otherwise env vars. Not configured → no "Login with Google" button; the rest
7// of the site keeps working. Google login NEVER grants admin rights.
8//
9// The redirect URI is derived from PUBLIC_BASE_URL (<base>/auth/google/callback),
10// or explicitly via GOOGLE_REDIRECT_URI. That exact URL must be listed in Google Cloud.
11
12import { getSetting } from '../services/SettingsService.js';
13
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';
17
18// Read dynamically (UI changes take effect without a restart). app_settings wins, 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(); } // not secret, used for the settings form
32export function clientSecretSet() { return !!clientSecret(); }
33export function googleConfigured() {
34 return !!(clientId() && clientSecret() && redirectUri());
35}
36
37export function authorizeUrl(state) {
38 const p = new URLSearchParams({
39 client_id: clientId(),
40 redirect_uri: redirectUri(),
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()}`;
48}
49
50export async function exchangeCode(code) {
51 const body = new URLSearchParams({
52 code,
53 client_id: clientId(),
54 client_secret: clientSecret(),
55 redirect_uri: redirectUri(),
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,
62 });
63 if (!r.ok) throw new Error(`Google token exchange failed: ${r.status}`);
64 return r.json(); // { access_token, id_token, ... }
65}
66
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 failed: ${r.status}`);
71 return r.json();
72}
Note: See TracBrowser for help on using the repository browser.