Navigando in rete col vostro browser o utilizzando un’app installata sul vostro smartphone vi sarà capitato di utilizzare qualche applicazione che, per fornirvi un servizio, ha bisogno di accedere ad alcuni vostri dati tipo (indirizzo mail, dati di contatto o altre tipologie di dati), ospitati nei vostri profili facebook, google, instagram, github o altro, per poi analizzarli, elaborarli ed infine fornirvi il servizio da voi richiesto. In casi come questi, ad un certo punto, compare una finestra o un riquadro che chiede la vostra autorizzazione a condividere i suddetti dati con l’applicazione che state usando (client), la finestra di autorizzazione vi informa, inoltre, sulla tipologia di dati che verranno condivisi. Dietro questo processo si nasconde il protocollo OAuth 2.0.
OAuth 2.0, sta per Open Authorization versione 2.0 ed è un protocollo standard aperto che consente una autorizzazione API (Application programming interface) sicura per lo scambio di dati tra applicazioni.
Attori del protocollo OAuth
Nel protocollo OAuth si distinguono i seguenti ruoli:
- Resource Owner (l’utente proprietario della risorsa/dati a cui l’applicazione vuole accedere)
- Resource server (server in cui risiedono i dati del resource owner)
- Authorization server (Server di autorizzazione in grado di autenticare il resource owner)
- Client (L’applicazione che ha bisogno di accedere ai dati presenti nel resource server)
Spesso i ruoli resource server e authorization server coincidono.
Descrizione del Processo di autorizzazione
Vi è più di un processo di autorizzazione (Grant type) gestito da Oauth, ma nel nostro caso illustreremo quello maggiormente utilizzato dalle applicazioni web, basato sulla richiesta di un token mediante un authorization code.
Lo scenario potrebbe essere il seguente:
Mentre il Resource Owner (utente) sta utilizzando un’applicazione web, il client lo reindirizza verso il server di autorizzazione (facebook, google ecc.), a questo punto il server richiede all’utente l’autorizzazione e se questa viene concessa, l’utente viene reindirizzato verso l’applicazione alla quale viene trasmesso un codice (authorization code). Una volta che il client ha ricevuto il suddetto codice, quest’ultimo fa un’altra richiesta, inviando al server il codice ottenuto e ricevendo in cambio un token che utilizzerà in seguito per interrogare le api del resource server ed accedere ai dati di proprietà del resource owner(utente) autorizzati e necessari . Il token che riceve il client è simile ad un pass che ha delle autorizzazioni limitate sia in termini di tempo che di accesso alle risorse (accesso limitato solo alle risorse/dati autorizzate dal resource owner).
Grafico esplicativo
Descrizione del processo illustrato nell’immagine:
- L’utente (resource owner) si collega ad un dominio per utilizzare un’applicazione (client)
- Il client, che in precedenza aveva registrato l’applicazione su un server (es. facebook, google, github, ecc.), ricevendo un client_id e un client_secret, fa una richiesta GET all’ authorization server
- L’authorization server chiede all’utente l’autorizzazione di accesso ad alcuni dati dell’utente e se questi la concede, allora il server risponde reindirizzando l’utente verso il client, inviandogli un authorization code
- Il client a questo punto fa una richiesta POST in cui invia il codice ricevuto e ottiene in risposta un access_token
- Una volta in possesso del token, il client può utilizzarlo per richiedere al resource server i dati necessari. queste richieste vengono fatte utilizzando delle API messe a disposizione del resource server.
ESEMPIO CONCRETO
Per mostrare il funzionamento di OAuth ho realizzato un esempio molto banale in cui una piccola applicazione web, ospitata nel mio dominio, chiede all’utente l’autorizzazione per accedere al suo indirizzo gmail e alla sua immagine di profilo, magari per poi procedere ad una registrazione o altro, sfruttando il fatto di ricevere dei dati già validati da google.
Nel nostro esempio ci limiteremo alla visualizzazione dei dati ricevuti in una pagina web.
Passo 1
Registriamo la nostra app su google, fornendo alcuni dati tra cui il nome dell’applicazione e un indirizzo di callback sarà un url del client verso la quale l’utente verrà rediretto, dopo aver concesso l’autorizzazione. Google ci fornirà un client_id e un Client_secret da utilizzare per autenticarlo durante gli scambi col server.
Per registrare una applicazione/progetto su google e ricevere i suddetti dati, utilizzare il seguente indirizzo:
https://console.developers.google.com/
Passo 2
A questo punto sul server che ospita il nostro dominio creiamo i file della nostra applicazione:
(il contenuto dei file è ridotto all’essenziale a scopo didattico e per focalizzare solo gli aspetti salienti di Oauth, se li si vuole utilizzare in altri contesti vanno organizzati meglio)
index.php (pagina principale dell’applicazione)
oauth.php (pagina che gestisce il processo di autenticazione)
profilo.php (pagina che sarà richiamata in background utilizzando ajax e che richiederà a google i dati del mio profilo fornendogli l’access token, in particolare i dati richiesti saranno indirizzo mail e url dell’immagine di profilo)
script.js (un file javascript che gestisce la chiamata asincrona al server)
Quando il browser dell’utente si posiziona sul file index.php, se l’applicazione non ha ricevuto l’access_token (registrato in una variabile di sessione), il client reindirizza l’utente al file oauth.php che a sua volta porta a termine il processo di autorizzazione utilizzando il protocollo oauth 2.0.
Se invece il client ha ricevuto già l’access_token e lo ha registrato in una variabile di sessione, allora viene mostrato all’utente un pulsante cliccando sul quale comparirà nella pagina la sua mail e la sua foto del profilo google.
Link alla DEMO https://www.francescochiriaco.it/testapi
Di seguito il codice in PHP
File index.php
<?php
session_start();
/* Controllo se l'access token è già stato ricevuto e registrato
nella variabile di sessione, altrimenti richiamo
lo script oauth.php per interagire con il server
utilizzando oauth 2.0 */
if(!isset($_SESSION["access_token"]) || empty($_SESSION["access_token"]))
{
header("location: oauth.php");
}
?>
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Test</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>
<script type="text/javascript" src="script.js"></script>
</head>
<body>
<div class="container-fluid">
<h1 class="alert alert-info text-center">Test Google oauth2</h1>
<div class="row">
<div class="col-xs-12 text-center" style="margin:auto auto">
<button id="test" class="btn btn-primary">DATI PROFILO</button>
</div>
</div>
<div class="row">
<div class="col-xs-12 text-center" style="margin: 100px auto">
<div id="response" class="text-center">
<!-- qui compariranno i dati di profilo -->
</div>
</div>
</div>
</div>
</body>
</html>
File oauth.php
<?php
session_start();
/* inizializzo variabili di sessione con credenziali client ecc. */
$_SESSION['client_id'] = 'inserire client id; // inserire il client_id ricevuto
$_SESSION['client_secret'] = 'inserire client secret'; // inserire il client_secret ricevuto
$_SESSION["redirect_uri"] = "https://www.francescochiriaco.it/testapi/oauth.php"; // URI funzione di callback registrata sul server
$_SESSION["scope"] = "https://www.googleapis.com/auth/userinfo.email"; // tipo di Autorizzazione richiesta
$_SESSION['resource_uri'] = 'https://www.francescochiriaco.it/testapi/index.php'; // Pagina principale dell'applicazione
if(isset($_GET["code"]))
$_SESSION['code'] = $_GET["code"];
else if(!isset($_SESSION['code']) && !isset($_GET["code"]))
$_SESSION['code'] = "";
if(!isset($_SESSION['access_token']))
$_SESSION['access_token'] = '';
$_SESSION['appname'] = 'testapi';
/* richiesta authorization code e poi token */
if(!isset($_SESSION['code']) || empty($_SESSION['code']))
{
$url = "https://accounts.google.com/o/oauth2/v2/auth?" . "client_id=" . $_SESSION['client_id'] . "&redirect_uri=" . $_SESSION['redirect_uri'] . "&response_type=code&scope={$_SESSION["scope"]}&access_type=offline";
header("location: {$url}");
}
else if((isset($_SESSION['code']) && !empty($_SESSION['code'])) && (!isset($_SESSION['access_token']) || empty($_SESSION['access_token'])))
{
$data = array("client_id" => $_SESSION['client_id'],"client_secret" => $_SESSION['client_secret'],"redirect_uri" => $_SESSION['redirect_uri'],"code" => $_SESSION['code'],"grant_type" => "authorization_code");
$url = "https://www.googleapis.com/oauth2/v4/token";
$cu = curl_init($url);
curl_setopt($cu,CURLOPT_POST,1);
curl_setopt($cu,CURLOPT_POSTFIELDS,http_build_query($data));
curl_setopt($cu,CURLOPT_HTTPHEADER,['content-type: application/x-www-form-urlencoded']);
curl_setopt($cu,CURLOPT_RETURNTRANSFER, true);
$dati = curl_exec($cu);
curl_close($cu);
$resp = json_decode($dati,true);
$_SESSION['access_token'] = $resp["access_token"];
$_SESSION['refresh_token'] = $resp["refresh_token"];
header("location: {$_SESSION['resource_uri']}");
}
?>
File profilo.php
<?php
session_start();
$url = "https://www.googleapis.com/oauth2/v2/userinfo";
$cu = curl_init($url);
curl_setopt($cu,CURLOPT_HTTPHEADER,["Authorization: Bearer {$_SESSION['access_token']}"]);
curl_setopt($cu,CURLOPT_RETURNTRANSFER, true);
$dati = curl_exec($cu);
$resp = json_decode($dati,true);
curl_close($cu);
// var_dump($resp);
$email = $resp["email"];
$img = $resp["picture"];
echo $email . "<br><br>" . "<img src={$img} />";
?>
File script.js
$(document).ready(function(){
$('#test').click(function() {
$.ajax({
url: "profilo.php",
type: "GET",
success: function( response ) {
$('#response').html(response );
}
});
});
});
Grazie mille!