UNPKG

simple-google-oauthentication

Version:

Minimal setup Google OAuth 2.0 middleware for Express.js apps with automatic login, session, and logout.

132 lines (112 loc) 4.11 kB
const express = require("express"); const axios = require("axios"); const qs = require("querystring"); const jwt = require("jsonwebtoken"); const cookieParser = require("cookie-parser"); const fs = require("fs"); const path = require("path"); const SECRET_FILE = path.join(process.cwd(), ".simple-google-oauth.json"); let oauthOptions = {}; function getOrCreateSecret(userProvidedSecret) { if (userProvidedSecret) { console.log("[simple-google-oauth] Using provided jwtSecret."); return userProvidedSecret; } if (fs.existsSync(SECRET_FILE)) { const data = JSON.parse(fs.readFileSync(SECRET_FILE)); console.log("[simple-google-oauth] Loaded jwtSecret from file."); return data.jwtSecret; } const newSecret = require("crypto").randomBytes(32).toString("hex"); fs.writeFileSync(SECRET_FILE, JSON.stringify({ jwtSecret: newSecret }, null, 2)); console.log("[simple-google-oauth] Generated and saved new jwtSecret."); return newSecret; } function simpleGoogleOAuth({ clientID, clientSecret, redirectURI, jwtSecret }) { const router = express.Router(); const secret = getOrCreateSecret(jwtSecret); oauthOptions = { clientID, clientSecret, redirectURI }; const cookieName = "auth_token"; router.use(cookieParser()); router.use((req, res, next) => { const token = req.cookies[cookieName]; if (token) { try { req.user = jwt.verify(token, secret); console.log(`[simple-google-oauth] JWT verified for user: ${req.user.email}`); } catch (e) { console.warn("[simple-google-oauth] Invalid JWT. Clearing user."); req.user = null; } } else { req.user = null; } next(); }); const callbackPath = new URL(redirectURI).pathname || "/callback"; router.get(callbackPath, async (req, res) => { console.log("[simple-google-oauth] Received callback with code:", req.query.code); try { const tokenRes = await axios.post( "https://oauth2.googleapis.com/token", qs.stringify({ code: req.query.code, client_id: clientID, client_secret: clientSecret, redirect_uri: redirectURI, grant_type: "authorization_code", }), { headers: { "Content-Type": "application/x-www-form-urlencoded" }, } ); console.log("[simple-google-oauth] Access token received from Google."); const { access_token } = tokenRes.data; const userRes = await axios.get("https://www.googleapis.com/oauth2/v2/userinfo", { headers: { Authorization: `Bearer ${access_token}` }, }); console.log("[simple-google-oauth] User info fetched:", userRes.data.email); const token = jwt.sign(userRes.data, secret, { expiresIn: "1h" }); res.cookie(cookieName, token, { httpOnly: true, secure: false, // set to true in production with HTTPS maxAge: 1000 * 60 * 60, }); console.log("[simple-google-oauth] User logged in and JWT cookie set."); res.redirect("/"); } catch (err) { console.error("[simple-google-oauth] OAuth flow failed:", err.message); res.status(500).send("OAuth failed"); } }); return router; } function login(req, res) { console.log("[simple-google-oauth] Initiating Google OAuth login..."); const url = `https://accounts.google.com/o/oauth2/v2/auth?` + qs.stringify({ client_id: oauthOptions.clientID, redirect_uri: oauthOptions.redirectURI, response_type: "code", scope: "openid email profile", access_type: "offline", prompt: "consent", }); console.log("[simple-google-oauth] Redirecting to:", url); res.redirect(url); } function logout(req, res) { res.clearCookie("auth_token"); console.log("[simple-google-oauth] User logged out. Cookie cleared."); res.redirect("/"); } function getUser(req) { return req.user || null; } module.exports = { simpleGoogleOAuth, login, logout, getUser, };