Linkedin Login con Javascript
Nel precedente post Linkedin Login con Postman abbiamo visto come consumare le API di linkedin attraverso postman, ora invece passiamo ai fatti rieseguendo tutti i passaggi con Javascript.
Per comodità utilizzeremo lo scaffolding di Parcel, dato che di partenza ha già tutto configurato ( ho scritto un post a riguardo Creare un progetto parceljs ), ma volendo si può integrare in qualsiasi altro scaffolding ad esempio webpack.
Per connetterci avremmo bisosgno quindi di un bottone “accedi con linkedin” e un div che farà da wrapper per restituire i nostri dati dopo l’autenticazione. In un file html quindi ci mettiamo il giusto necessario:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Linkedn</title>
</head>
<body>
<img src="https://content.linkedin.com/content/dam/developer/global/en_US/site/img/signin-button.png" alt="linkedin" id="linkedin-login">
<div id="profile"></div>
<script src="./index.js"></script>
</body>
</html>
Passiamo alla parte di Javascript ed iniziamo ad installare le dipendenze, ci serviranno:
- axios: per le richieste http
- querystring: per convertire in stringa i parametri da un oggetto
- store: per memorizzare i dati su local storage
quindi da terminale:
npm i --save axios querystring store
e sul nostro file Javascript
import axios from 'axios';
import querystring from 'querystring';
import store from 'store';
Creiamo un file .env sulla root del progetto con i seguenti parametri
CLIENT_ID=${tuo-cliente-id}
CLIENT_SECRET=${tuo-cliente-secret}
REDIRECT_URI=${tuo-redirect}
Con il .env avremo ben separati la parte di variabili di ambiente dal codice, ed avere quindi la possibilità di diversi setting per locale e produzione; ovviamente questo file sarebbe utile tracciarlo sul .gitignore per escluderlo dal versionamento.
Iniziamo a dichiarare un pò di variabili sul Javascript, tra cui anche quelle di ambiente:
const client_id = process.env.CLIENT_ID;
const client_secret = process.env.CLIENT_SECRET;
const redirect_uri = process.env.REDIRECT_URI;
const corsUrl = 'https://cors-anywhere.herokuapp.com/'; // Proxy per bypassare CORS
// Endpoint
const url = {
auth : 'https://www.linkedin.com/oauth/v2/authorization',
token : 'https://www.linkedin.com/oauth/v2/accessToken',
me : 'https://api.linkedin.com/v2/me'
}
const parameters = new URLSearchParams(window.location.search); // Per ottenere i parametri GET
const btnLogin = document.getElementById('linkedin-login'); // Bottone
const wrapper = document.getElementById('profile'); // Wrapper
Le funzioni javascript per la login API di Linkedin
Ora che abbiamo tutte le variabili di cui abbiamo bisogno, possiamo iniziare a scrivere le funzioni che richiameranno gli endpoint, e restituiranno le informazioni che ci occorrono. La prima funziona che ci occorre è quella che apre la login di Linkedin e ci restituisce il parametro code:
const LnkLogin = ()=> {
const params = {
response_type:'code',
client_id: client_id,
state: Math.floor(Date.now() / 1000),
redirect_uri: redirect_uri,
scope: 'r_liteprofile r_emailaddress w_member_social'
}
const urlWindow = `${getEndpoint('auth',false)}?${querystring.stringify(params)}`;
window.open(urlWindow,'_self');
}
Dobbiamo richiedere il token di sessione a Linkedin, imprescindibile per eseguire tutte le future chiamate. Con javascript inizializzeremo una promises:
const LnkToken = ()=> {
const config = {
grant_type : 'authorization_code',
client_id : client_id,
client_secret : client_secret ,
redirect_uri : redirect_uri,
code : parameters.get('code')
}
return new Promise((resolve, reject) => {
axios.post(getEndpoint('token'),querystring.stringify(config),{
headers: {
'content-type': 'application/x-www-form-urlencoded',
},
})
.then ( result => {
resolve(result.data.access_token)
})
.catch( err => reject(err) )
});
}
Ora che abbiamo ottenuto il token, siamo autenticati con Linkedin e d’ora in poi dovremmo passarlo nell’header della richiesta con un Authorization Bearer. Questa chiamata all’API ci permetterà di ottenere i nostri dati personali come nome, cognome ed indirizzo email.
const LnkMe = ()=> {
const { token } = store.get('linkedin');
return new Promise((resolve, reject) => {
axios.get(getEndpoint('me'),{
headers: {
'Authorization': `Bearer ${token}`,
},
})
.then ( response => {
if(response.data?.id) {
store.set('linkedin',{
...store.get('linkedin'),
...response.data
})
resolve(response.data)
}
reject(err)
})
.catch( err => reject(err) )
});
}
Non è previsto un endpoint per eseguire il logout, semplicemente andremmo a distruggere il token, i dati che abbiamo memorizzato e reinizializziamo l’applicazione.
/**
* Eseguo il logout
*/
const LnkLogout = () => {
const btnExit = document.getElementById('logout');
btnExit.addEventListener('click',()=> {
store.clearAll();
btnLogin.style.display = 'block';
wrapper.innerHTML = '';
window.location.search = '';
init();
})
}
Per comodità, mettiamo tutto in una funziona l’output dei dati
/**
* Stampo i miei dati
*/
const LnkProfile = ()=> {
const { localizedFirstName: firstname, localizedLastName: lastname } = store.get('linkedin');
wrapper.innerHTML = `
Benvenuto <strong>${firstname} ${lastname}</strong> | <a href="javascript:void(0)" id="logout">Logout</a>
`
return;
}
La funzione di inizializzazione verifica in quale stato siamo, e richiama gli eventi necessari
const init = ()=> {
const linkedin = store.get('linkedin');
// Se sono loggato, esiste l'oggetto linkedin, e quindi il token
if( linkedin && linkedin.token ){
btnLogin.style.display = 'none' // Nascondo il bottone
LnkProfile(); // Stampo i dati
LnkLogout(); // Se clicco su logout, distruggo la sessione
}
// Abbiamo appena ottenuto il CODE ma non ancora il token
else if(parameters.get('code') && !linkedin?.token ){
btnLogin.style.display = 'none' // nascondo il bottone
LnkToken() // Avvio la catena di richieste per connettermi a linkedin
.then( token => store.set('linkedin',{ token: token }) )
.then( ()=> LnkMe() )
.then( ()=> LnkProfile() )
.then( ()=> LnkLogout() )
.catch( err => console.log(err) )
}
// Lo stato di partenza, ancora non ho nulla, devo intereccettare il click del bottone
else {
btnLogin.addEventListener('click', ()=> LnkLogin() );
}
}
Infine per far partire l’applicazione, basterà richiamare la funzione init()
L’applicazione completa è disponibile su github Linkedin Login
Nel prossimo post, vedremo come Pubblicare un post su linkedin tramite le API