source: Klonkt/src/config/google.js@ c80e78b

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

auth: replace username/password with Google login

Listeners (and the owner) now log in via Google instead of a local
username/password account. This lowers the barrier to commenting and
removes the home-built password/registration system.

  • src/config/google.js: raw OAuth2 helpers (authorize/token/userinfo) via the built-in fetch, config-driven. Boot keeps working without credentials.
  • src/routes/auth.js: /auth/google + /auth/google/callback (find-or-create user on email, ADMIN_EMAIL -> god, set session). login/register/reset POST handlers removed; /login now shows the Google button.
  • database.js: idempotent column users.google_sub.
  • account.js + account.ejs: change-password removed.
  • auth-login.ejs / welcome.ejs: Google button instead of password form.
  • shared-styles.ejs: .btn-google styling.
  • .env.example: GOOGLE_CLIENT_ID/SECRET/REDIRECT_URI + ADMIN_EMAIL.

Existing users are matched on email (owner retains their site).
DO NOT deploy to roboburr until the Google credentials are in .env, otherwise
the owner locks themselves out.

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

  • Property mode set to 100644
File size: 2.0 KB
Line 
1// Google OAuth2 (per-instance). Raw via de ingebouwde fetch — geen passport-dep.
2// Config via env (per instance, in .env):
3// GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET
4// GOOGLE_REDIRECT_URI = https://<dit-domein>/auth/google/callback
5// ADMIN_EMAIL = de Google-mail die owner/admin (god) is op deze instance
6// Niet geconfigureerd? Dan booten we gewoon door; /auth/google meldt netjes
7// "nog niet geconfigureerd" i.p.v. te crashen.
8
9const CLIENT_ID = process.env.GOOGLE_CLIENT_ID || '';
10const CLIENT_SECRET = process.env.GOOGLE_CLIENT_SECRET || '';
11const REDIRECT_URI = process.env.GOOGLE_REDIRECT_URI || '';
12
13const AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth';
14const TOKEN_URL = 'https://oauth2.googleapis.com/token';
15const USERINFO_URL = 'https://openidconnect.googleapis.com/v1/userinfo';
16
17export function googleConfigured() {
18 return !!(CLIENT_ID && CLIENT_SECRET && REDIRECT_URI);
19}
20
21export function authorizeUrl(state) {
22 const p = new URLSearchParams({
23 client_id: CLIENT_ID,
24 redirect_uri: REDIRECT_URI,
25 response_type: 'code',
26 scope: 'openid email profile',
27 state,
28 access_type: 'online',
29 prompt: 'select_account',
30 });
31 return `${AUTH_URL}?${p.toString()}`;
32}
33
34export async function exchangeCode(code) {
35 const body = new URLSearchParams({
36 code,
37 client_id: CLIENT_ID,
38 client_secret: CLIENT_SECRET,
39 redirect_uri: REDIRECT_URI,
40 grant_type: 'authorization_code',
41 });
42 const r = await fetch(TOKEN_URL, {
43 method: 'POST',
44 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
45 body,
46 });
47 if (!r.ok) throw new Error(`Google token-exchange faalde: ${r.status} ${await r.text().catch(() => '')}`);
48 return r.json(); // { access_token, id_token, ... }
49}
50
51// Returns { sub, email, email_verified, name, picture }.
52export async function fetchUserinfo(accessToken) {
53 const r = await fetch(USERINFO_URL, { headers: { Authorization: `Bearer ${accessToken}` } });
54 if (!r.ok) throw new Error(`Google userinfo faalde: ${r.status}`);
55 return r.json();
56}
Note: See TracBrowser for help on using the repository browser.