Come implementare l’autenticazione OAuth2 Google in NodeJS utilizzando Passport

In questo articolo descriviamo come implementare l’autenticazione tramite Google in una applicazione web in Node.js, utilizzando la libreria Passport.

Per prima cosa, accediamo alla Cloud Console di Google https://console.cloud.google.com/ per ottenere due codici che ci serviranno nel seguito, il client ID e il client secret.

Dal menu a tendina in alto a sinistra, selezioniamo un progetto esistente o creiamone uno nuovo, cliccando sul pulsante “NUOVO PROGETTO”

Assegniamo un nome al nostro progetto e clicchiamo sul bottone “CREA”.

Selezioniamo il progetto e dal menu a sinistra selezioniamo la voce “API e servizi” > “Credenziali”

Clicchiamo su pulsante “CREA CREDENZIALI” > “ID client OAuth”

Ci verrà chiesto di configurare la schermata di consenso. Selezioniamo “Interno” o “Esterno” se vogliamo circoscrivere l’applicazione ai solo utenti della nostra organizzazione o estenderla a chiunque abbia un account Google.

A questo punto ci vengono richieste alcune informazioni sull’applicazione, come nome, email per assistenza utenti, email dello sviluppatore etc.

Clicchiamo su “SALVA E CONTINUA” e procediamo con i passaggi successivi, quindi torniamo alla dashboard.

Selezioniamo nuovamente “CREA CREDENZIALI” > “ID client OAuth”.

Selezioniamo come tipo di applicazione, la voce “Applicazione web” e assegniamole un nome e specifichiamo come “URI di reindirizzamento autorizzati”, la url che andremo a esporre http://<TUO-DOMINIO>/auth/google/callback . quindi clicchiamo sul pulsante “CREA”. A questo punto si aprirà una popup con i nuovi ID client e client secret generati

A questo punto inizializziamo la nostra applicazione Node.js. Creiamo una cartella e posizioniamoci al suo interno. Apriamo una console e digitiamo:

npm init

Quindi installiamo tutte le librerie di cui abbiamo bisogno nel progetto:

npm install express ejs express-session passport passport-google-oauth --save

Creiamo un file index.js nella cartella di progetto e incolliamo il codice che segue

const express = require('express');
const ejs = require('ejs');
const app = express();
const session = require('express-session');
const port = process.env.PORT || 3000;
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;

const GOOGLE_CLIENT_ID = '<CLIENT_ID>';
const GOOGLE_CLIENT_SECRET = '<CLIENT_SECRET>';
const GOOGLE_REDIRECT_URI = '<YOUR-DOMAIN>/auth/google/callback';

app.use(session({
  resave: false,
  saveUninitialized: true,
  secret: 'SECRET' 
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new GoogleStrategy({
    clientID: GOOGLE_CLIENT_ID,
    clientSecret: GOOGLE_CLIENT_SECRET,
    callbackURL: GOOGLE_REDIRECT_URI
  },
  function(accessToken, refreshToken, profile, done) {
      userProfile=profile;
      return done(null, userProfile);
  }
));

app.listen(port , () => console.log('App in ascolto sulla porta ' + port));

var userProfile;

checkAuthenticated = (req, res, next) => {
  if (req.isAuthenticated()) {
    return next()
  } else {
    res.redirect("/login")
  }
}

app.get('/home', checkAuthenticated, (req, res) => {
    res.render("home.ejs", {
      user: req.user
    })
  }
);

app.get('/auth/google', 
  passport.authenticate('google', { scope : ['profile', 'email'] })
);
 
app.get('/auth/google/callback', 
  passport.authenticate('google', {
    successRedirect: '/home',
    failureRedirect: '/login'
  })
);

app.get('/login', (req, res) => {
    res.render("login.ejs")
  }
);

app.get("/logout", (req, res) => {
  req.logout(req, err => {
    if (err) {
      return next(err);
    }
    req.session = null;
    res.redirect("/login");
  });
})

passport.serializeUser(function(user, cb) {
  cb(null, user);
});

passport.deserializeUser(function(obj, cb) {
  cb(null, obj);
});

Il codice importa i moduli e le dipendenze necessari quindi inizializza alcune costanti che utilizzeremo per effettuare l’autenticazione su Google

const GOOGLE_CLIENT_ID = ”;
const GOOGLE_CLIENT_SECRET = ”;
const GOOGLE_REDIRECT_URI = ‘/auth/google/callback’;

Quindi si configurano i middleware session e passport e si definisce la strategia Google OAuth2, passando come parametri l’ID client, il client secret e l’URI di reindirizzamento. Il codice imposta anche una funzione di callback che viene richiamata quando l’utente viene autenticato e che memorizza il profilo dell’utente in una variabile chiamata userProfile.

Quindi viene impostata l’applicazione Express e si definisce la porta su cui il server rimane in ascolto.

Successivamente viene definita la funzione checkAuthenticated che verifica la presenza nella richiesta del flag di autenticazione e in caso di esito negativo redirige alla pagina di login.

proteggiamo tutte le rotte dell’applicazione che vogliamo mettere sotto autenticazione, utilizzando la funzione suddetta

app.get('/home', checkAuthenticated, (req, res) => {
      res.render("home.ejs", {
      user: req.user
    })
  }
);

Il codice imposta successivamente le rotte per l’applicazione e le funzioni per la serializzazione e la deserializzazione dell’oggetto utente.

Quando un utente accede ad un percorso protetto la pagina viene rediretta sulla pagina di login. Quando l’utente fa clic sul pulsante “Accedi con Google”, verrà reindirizzato al percorso di autenticazione di Google, dove verrà richiesto di accedere con il proprio account Google.

Una volta che l’utente è stato autenticato, verrà reindirizzato alla home, dove le informazioni del profilo dell’utente vengono mostrate a video.

Creiamo la pagina “login.ejs” che deve contenere il seguente frammento di codice che renderizza il link per l’accesso

<a href="/auth/google">Accedi con Google</a></div>

e la pagina di atterraggio dopo l’autenticazione, “home.ejs”, che potrebbe contenere ad esempio un messaggio di benvenuto.

Benvenuto <%= user.given_name %> <%= user.family_name %>!