Nel precedente articolo abbiamo introdotto i concetti alla base del protocollo OAuth 2, descrivendo i principali flussi di autorizzazione previsti.
In questo articolo passeremo dalla teoria alla pratica: per meglio comprendere i meccanismi definiti nello standard eseguiremo manualmente i vari passaggi del flusso di autenticazione. Non utilizzeremo uno specifico linguaggio di programmazione, ma ci avvarremo di strumenti e metodi indipendenti da linguaggi o framework.
Registrazione dell'applicazione
Supponiamo di voler realizzare un'applicazione che sfrutti le API di GitHub per mostrare i repositories dell'utente.
Per fare questo dobbiamo innanzi tutto "registrare" la nostra applicazione su GitHub, accedendo alla sezione Developer Settings > OAuth Apps. Clicchiamo sul pulsante "Register a new application":
Verrà mostrato il form di registrazione dell'applicazione:
Diamo un nome all'applicazione (Application Name),indichiamo l'indirizzo della pagina principale (Homepage URL),una breve descrizione (Application description) e infine l'url alla quale dovrà essere inviato l'Authorization Token dopo che l'utente avrà concesso l'autorizzazione (Authorization callback URL, che corrisponde alla redirect uri nello standard OAuth).
Una volta confermati i dati, clicchiamo sul pulsante "Register application". Saremo reindirizzati alla pagina di riepilogo, dove ci verranno mostrati i parametri Client ID e Client Secret assegnati alla nostra applicazione. Per ragioni di sicurezza, nel corso dell'articolo useremo ovviamente dei valori fittizi per questi parametri.
Simulazione del processo
GitHub supporta solamente il flusso Authorization Code, pertanto dovremo:
- Concedere l'accesso alle risorse protette (i repositories) e richiedere l'Authorization Token
- Richiedere la generazione dell'Access Token
- Utilizzare l'Access Token per richiedere la lista dei repositories
1. Autorizzazione e generazione dell'Authorization Token
Il primo step richiede l'utilizzo di un browser per permettere l'esplicita autorizzazione da parte dell'utente.
L'endpoint di autorizzazione di GitHub è https://github.com/login/oauth/authorize, pertanto dobbiamo digitare questo url nella barra degli indirizzi, passando anche i seguenti parametri:
- response_type: indica il tipo di flusso che vogliamo utilizzare (nel nostro caso code).
- client_id: il valore del Client ID assegnato all'applicazione.
- redirect_uri: l'indirizzo (in formato urlencoded) a cui l'Authorization Server dovrà reindirizzare dopo l'autorizzazione esplicita dell'utente. Questo parametro deve corrispondere al valore dell'Authorization callback URL specificato in fase di registrazione dell'applicazione.
- scope: la lista (separata da "+") delle autorizzazioni di cui la nostra applicazione ha bisogno e che vogliamo richiedere all'utente. In questo caso vogliamo avere accesso ai repository dell'utente, perciò indicheremo lo scope repo. La lista completa degli scope disponibili è consultabile alla pagina dedicata.
- code_challenge: questo parametro non è obbligatorio, fa parte dell'estensione PKCE utilizzata per limitare il rischio di intercettazione dell'Authorization Token. Si tratta di un hash di un altro parametro, il code_verifier che deve essere generato dall'applicazione prima di iniziare il flusso di autorizzazione. In questo caso, supponiamo di utilizzare un code_verifier "12345".
- code_challenge_method: indica la funzione di hash che è stata usata per generare il code_challenge a partire dal code_verifier. Nel nostro caso utilizzeremo SHA256 come funzione di hash.
Apriamo quindi il browser e colleghiamoci all'url:
https://github.com/login/oauth/authorize
?response_type=code
&client_id=CLIENTID
&redirect_uri=REDIRECTURI
&scope=repo
&code_challenge=5994471abb01112afcc18159f6cc74b4f511b99806da59b3caf5a9c173cacfc5
&code_challenge_method=S256
Ci verrà a questo punto presentata la pagina di autenticazione di GitHub e, una volta autenticati, la pagina di richiesta di autorizzazione, che ci informerà che la nostra applicazione desidera accedere ai repositories dell'utente.
Una volta concessa l'autorizzazione, l'Authorization Server reindirizzerà il browser al redirect url specificato in fase di registrazione, valorizzando il parametro GET "code" con l'Authorization Token.
2. Richiesta dell'Access Token
Bene, possiamo ora procedere con la richiesta dell'Access Token...
I parametri necessari per richiedere l'Access Token sono:
- code: corrisponde all'Authorization Token restituito in precedenza dall'authorization server
- redirect_uri: corrisponde all'url indicata in fase di registrazione dell'applicazione
- client_id: il Client ID assegnato all'applicazione
- client_secret: il Client Secret assegnato all'applicazione
- code_verifier: se stiamo utilizzando l'estensione PKCE, deve corrispondere al codice generato inizialmente e dal quale è stato generato il code_challenge. Nel caso in cui l'hash del code_verifier passato non corrisponda al code_challenge, la richiesta verrà rifiutata.
Apriamo un terminale e digitiamo il comando:
curl https://github.com/login/oauth/access_token --data "grant_type=authorization_code \
&code=AUTHORIZATIONCODE \
&redirect_uri=REDIRECTURI \
&client_id=CLIENTID \
&client_secret=CLIENTSECRET \
&code_verifier=12345"
Il risultato dovrebbe essere una cosa del tipo:
access_token=ACCESSTOKEN&scope=repo&token_type=bearer
Come facile intuire, l'Access Token corrisponde al valore del parametro access_token.
GitHub non prevede una scadenza per gli Access Token, di conseguenza non espone alcun tipo di flusso di "rinnovo" dei token. Se il flusso "Refresh Token" fosse supportato, la risposta riporterebbe ulteriori parametri:
- expires_in: corrisponde al numero di secondi dopo il quale l'access token non sarà più valido
- refresh_token: indica un ulteriore token da utilizzare per generare un nuovo Access Token quando quello corrente non sarà più valido.
3. Utilizzo dell'Access Token
Con l'Access Token possiamo ora effettuare una richiesta per ottenere i repositories dell'utente, passando l'Access Token all'interno dell'header "Authorization":
curl https://api.github.com/user/repos -H "Authorization: Bearer ACCESSTOKEN"
Il risultato sarà un array in formato json contenente tutti i repositories dell'utente. Alla nostra applicazione non resterà che interpretare la risposta per estrarre le informazioni necessarie.
Conclusioni
Il protocollo OAuth è abbastanza semplice, e proprio grazie a questo è sempre più utilizzato per proteggere l'accesso alle risorse sul web. Nonostante la sua semplicità, molte sono le sfaccettature e le eccezioni di cui è necessario tenere conto per realizzare un'applicazione che sia pienamente conforme alle specifiche.
Nel corso di questo articolo abbiamo visto solamente una tipologia di flusso, ma il protocollo definisce altre modalità di interazione e flussi operativi.
Nel prossimo articolo vedremo l'utilizzo di oauth2_client, una libreria Flutter che permette non solo di interagire in maniera semplice e veloce con i principali provider OAuth, ma permette la creazione con poche righe di codice di client custom per l'interfacciamento con qualsiasi server OAuth.