import { Router } from 'express' import { AuthorizationCode } from 'simple-oauth2' import fetch from 'node-fetch' import { DatabaseConnection, getUser, createUser } from './db/database' import { UserId } from '../shared/model' import { SessionService } from './routes' import { prependBaseUrl } from '../shared/utils' export function setupOAuth(r: Router, db: DatabaseConnection, sessions: SessionService) { const config = { client: { id: process.env.OAUTH_CLIENT_ID ?? '', secret: process.env.OAUTH_CLIENT_SECRET ?? '', }, auth: { authorizePath: process.env.OAUTH_AUTH_URL ?? '', tokenHost: process.env.OAUTH_TOKEN_HOST ?? '', tokenPath: process.env.OAUTH_TOKEN_PATH ?? '', }, } const conf = { redirect_uri: process.env.OAUTH_REDIRECT_URL ?? '', scope: process.env.OAUTH_SCOPES ?? '', } const client = new AuthorizationCode(config) const authorizationUri = client.authorizeURL({ redirect_uri: conf.redirect_uri, scope: conf.scope, state: '', }) r.get('/redirect', (req, res) => { res.redirect(authorizationUri) }) // Callback service parsing the authorization token and asking for the access token r.get('/callback', async (req, res) => { const code = req.query.code as string const options = { code, redirect_uri: conf.redirect_uri, } try { const accessToken = await client.getToken(options) console.log(accessToken.token.access_token) const userInfo = await ( await fetch(process.env.OAUTH_USER_INFO_URL ?? '', { method: 'GET', headers: { Authorization: 'Bearer ' + accessToken.token.access_token, }, }) ).json() type UserInfo = { name: string; email: string } // Parse user info into a sensible struct const authUser = { id: (userInfo as UserInfo).email.split('@')[0] as UserId, fullName: (userInfo as UserInfo).name .split(' ') .map(s => s.substring(0, 1) + s.substring(1).toLowerCase()) .join(' '), } const user = await getUser(db, authUser.id) if (!user) { await createUser(db, { id: authUser.id, fullName: authUser.fullName, role: 'student', }) } res.cookie('sid', sessions.createSession(authUser.id), { maxAge: 1000 * 60 * 60 * 24 * 7 }) return res.status(200).redirect(prependBaseUrl('/')) } catch (error) { console.error('Access Token Error', error.message) return res.status(500).redirect(prependBaseUrl(`/error?message=${encodeURIComponent('Autenticazione fallita')}`)) } }) }