parent
20253a8872
commit
317d33106c
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 65 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 106 KiB |
@ -0,0 +1,170 @@ |
|||||||
|
{% extends "base.html" %} |
||||||
|
|
||||||
|
{% block content %} |
||||||
|
<style> |
||||||
|
.url { |
||||||
|
color: #000088; |
||||||
|
font-family: Courier; |
||||||
|
} |
||||||
|
</style> |
||||||
|
<h1>OAuth</h1> |
||||||
|
|
||||||
|
<p>Heb je wel eens gebruik gemaakt van een API van Twitter, Facebook of Google? Dan heb je waarschijnlijk te maken gehad <strong>OAuth</strong>, de technologie die je toestemming verleent om gebruik te maken van die API's.</p> |
||||||
|
|
||||||
|
<p>Er zijn veel misverstanden over OAuth waardoor het vaak verkeerd begrepen wordt en er veel frictie ontstaat ontstaat tussen de API en de ontwikkelaar. Het is bijvoorbeeld niet ontworpen om enkel mee in te loggen, hoewel het daar wel veel voor gebruikt wordt. Deze week gaan we kijken naar het probleem van authoriseren en hoe OAuth dat oplost.</p> |
||||||
|
|
||||||
|
<p>We nemen als voorbeeld de Poespas bank. Een simpele website waarmee gebruikers kunnen inloggen met een gebruikersnaam en wachtwoord. Als ze ingelogd zijn zien ze hun huidige saldo. Ze hebben ook een simpele API waarmee gebruikers hun saldo kunnen checken.</p> |
||||||
|
|
||||||
|
<h3>Simpele authenticatie</h3> |
||||||
|
|
||||||
|
<p>Een simpele manier om de saldo API te implementeren is om rechtstreeks je gebruikersnaam en wachtwoord mee te geven in de API request. De server checkt of de inloggegevens correct zijn en geeft de saldo informatie terug van die gebruiker terug. Uiteraard moet dit alles over een beveiligde verbinding gebeuren, maar als dat zo is is het in theorie een veilige oplossing.</p> |
||||||
|
|
||||||
|
<figure> |
||||||
|
<img src="static/img/auth_basic.png"> |
||||||
|
</figure> |
||||||
|
|
||||||
|
<p>Veel echte API's werkte vroeger op deze manier (vaak op basis van <a href="http://en.wikipedia.org/wiki/Basic_access_authentication">HTTP Authentication</a>). En zolang alles over een beveiligde verbinding tussen de gebruiker en de server loopt is alles veilig. De problemen beginnen echter als een derde partij betrokken raakt bij onze API.</p> |
||||||
|
|
||||||
|
<p>Een startup heeft de <i>BudgetApp</i> ontwikkelt, een nieuwe app die laat zien hoeveel saldo je per maand op je rekening hebt staan. Ze maken gebruik van de Poespas API om het saldo van de gebruiker op te halen. Maar om die API te kunnen gebruiken hebben ze de gebruikersnaam en het wachtwoord van de gebruiker nodig. Op hun inlogscherm vragen ze daarom om de inloggegevens zodat de app goed kan werken.</p> |
||||||
|
|
||||||
|
<figure> |
||||||
|
<img src="static/img/auth_basic_app.png"> |
||||||
|
</figure> |
||||||
|
|
||||||
|
<p>Het probleem met deze manier van authenticeren wordt nu snel duidelijk: de app krijgt de gebruikersnaam en wachtwoord van de gebruiker in handen. Daarmee kunnen ze niet alleen het saldo kunnen ophalen met de API. Maar ook alle andere dingen die de gebruiker kan zoals bijvoorbeeld inloggen, geld overschrijven en wachtwoord veranderen.</p> |
||||||
|
|
||||||
|
|
||||||
|
<p>Om deze situatie te voorkomen willen we een autorisatiesysteem waarbij de app wel een sleutel krijgt om de API te gebruiken, maar niet het wachtwoord van de gebruiker zelf. Dat moet strict geheim blijven.</p> |
||||||
|
|
||||||
|
<h3>Enter OAuth</h3> |
||||||
|
|
||||||
|
...Access token verhaal... |
||||||
|
|
||||||
|
<h3>autorisatie</h3> |
||||||
|
|
||||||
|
<p>Deze site heeft ook een API die te vinden is op: <a href="/api/hallo">/api/hallo</a>. Die mag je uiteraard alleen gebruiken als je een access token hebt, als je gewoon op de link klikt krijg je een lege 403 pagina (Forbidden). We gaan alle stappen doorlopen om te komen tot de almachtige access token waarmee we de API kunnen aanroepen.</p> |
||||||
|
|
||||||
|
<p>De eerste stap bij een OAuth provider is om een client aan te maken. Daarmee weet de site altijd wie het is die de API aanroep doet. Voor deze opdracht kan je die aanmaken op <a href="/o/applications/">deze pagina</a>. Maak je eigen applicatie met de volgende gegevens:</p> |
||||||
|
|
||||||
|
<ul> |
||||||
|
<li><b>Name</b>: mag je zelf kiezen</li> |
||||||
|
<li><b>Client id</b>: mag je zelf kiezen, maar moet wel uniek zijn</li> |
||||||
|
<li><b>Client secret</b>: mag je zelf kiezen</li> |
||||||
|
<li><b>Client type</b>: Public</li> |
||||||
|
<li><b>Authorization grant type</b>: Authorization code</li> |
||||||
|
<li><b>Redirect uris</b>: http://example.com/ (mag ook een andere onzin URL zijn)</li> |
||||||
|
</ul> |
||||||
|
|
||||||
|
<figure> |
||||||
|
<img src="static/img/oauth_register.png" style="width: 50%"> |
||||||
|
</figure> |
||||||
|
|
||||||
|
<div class="question"> |
||||||
|
<span class="question-string">Wat is de client_id die je hebt geregistreerd?</span> |
||||||
|
<div class="points"><span class="question-points">5</span> punten</div> |
||||||
|
<input class="question-input" name="oauth_client_id" value="{{ answers.oauth_client_id }}"></input> |
||||||
|
</div> |
||||||
|
|
||||||
|
<p>Elke OAuth server heeft twee endpoints (lees: URL's): de autorisatie endpoint en de token endpoint. Hieronder zie je de endpoints van een aantal bekende servers:</p> |
||||||
|
|
||||||
|
<table border="1" cellpadding="4"> |
||||||
|
<tr> |
||||||
|
<th>Service</th> |
||||||
|
<th>Authorization endpoint</th> |
||||||
|
<th>Token endpoint</th> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td>Dit vak</td> |
||||||
|
<td>http://sec1.aii.avans.nl/o/authorize/</td> |
||||||
|
<td>http://sec1.aii.avans.nl/o/token/</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td>GitHub</td> |
||||||
|
<td>https://github.com/login/oauth/authorize</td> |
||||||
|
<td>https://github.com/login/oauth/access_token</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td>Google</td> |
||||||
|
<td>https://accounts.google.com/o/oauth2/auth</td> |
||||||
|
<td>https://accounts.google.com/o/oauth2/token</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td>Facebook</td> |
||||||
|
<td>https://www.facebook.com/dialog/oauth</td> |
||||||
|
<td>https://graph.facebook.com/oauth/access_token</td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
|
||||||
|
<p>De autorisatie endpoint is de URL waar je de gebruiker heenstuurt om hem te laten inloggen op de website en om op 'Toestaan' te laten klikken. Deze site redirect daarna weer terug naar je eigen site / app met een speciale autorisatie code. De token endpoint is de OAuth API waar we al onze access tokens uit kunnen halen, maar dan hebben we wel eerst die autorisatie code nodig.</p> |
||||||
|
|
||||||
|
<p>Om te authoriseren hebben we de volgende URL parameters nodig: (<a href="http://tools.ietf.org/html/rfc6749#section-4.1.1">documentatie</a>)</p> |
||||||
|
|
||||||
|
<ul> |
||||||
|
<li><b>response_type</b>: "token" of "code". Met "token" krijg je direct een access token in de redirect URL. Handig als je de API maar 1x hoeft te gebruiken. Minder handig als je de API langer wilt blijven gebruiken, want access tokens blijven vaak niet langer dan een uur geldig. Dan moet je de gebruiker elk uur opnieuw laten inloggen. Met "code" krijg je een autorisatie code die je kan inwisselen voor een speciale refresh_token, daar kan je tot in de oneindigheid nieuwe access tokens mee maken. <i>Voor deze opdracht gebruiken we "code"</i>.</li> |
||||||
|
<li><b>client_id</b>: Jouw gekozen client id</li> |
||||||
|
<li><b>redirect_uri</b>: optioneel, en eigenlijk ook redundant. Want die geef je ook vaak op als je je registreert als client bij de provider. Als de gebruiker op 'Toestaan' heeft geklikt wordt hij naar deze URL teruggestuurt met de autorisatie code of access token</li> |
||||||
|
<li><b>scope</b>: optioneel, kan je mee aangeven welke gedeeltes van de API je wilt kunnen gebruiken</li> |
||||||
|
<li><b>state</b>: optioneel, een string die je kan meegeven die ook weer wordt teruggestuurd als de gebruiker wordt terug geredirect. Kan handig zijn.</li> |
||||||
|
</ul> |
||||||
|
|
||||||
|
<p>Een voorbeeld van een autorisatie URL is: <span class="url">http://sec.aii.avans.nl/o/authorize/?client_id=(CLIENT_ID)&response_type=code</span></p> |
||||||
|
|
||||||
|
<div class="question"> |
||||||
|
<span class="question-string">Autoriseer met je eigen client id. Welke autorisatie code heb je gekregen?</span> |
||||||
|
<div class="points"><span class="question-points">5</span> punten</div> |
||||||
|
<input class="question-input" name="oauth_authorization_code" value="{{ answers.oauth_authorization_code }}"></input> |
||||||
|
</div> |
||||||
|
|
||||||
|
<h3>Access tokens in zicht</h3> |
||||||
|
|
||||||
|
<p>Ok, we hebben nu een autorisatie code. Met die code heb je nu een bewijsje dat de gebruiker recentelijk jouw client heeft geautoriseerd. Maar na dat alles hebben we nog steeds niet die albelangrijke access tokens die ons toegang geven tot de API. Om daar aan te komen moeten we onze autorisatie code inwisselen bij de token endpoint voor een refresh token en een access token.</p> |
||||||
|
|
||||||
|
<p>Dit lijkt allemaal nodeloos complex, waarom geeft OAuth nadat de gebruiker zijn zege heeft gegevens ons niet meteen een refresh_token en een access_token? Waarom moet dat nou weer via een aparte 'autorisatie code'? De reden hiervoor is is dat OAuth ontworpen is rond het principe dat webapplicatie's access_token moeten kunnen krijgen, zonder dat de gebruiker die te zien krijgt. De gebruiker kan niet zelf nieuwe access tokens ophalen omdat hij niet de client_secret heeft.</p> |
||||||
|
|
||||||
|
<p>Om de access_token en de refresh_token te krijgen moeten we POST requests versturen naar de token endpoint. Testen met POST requests is het handigst om met een tool te doen. In de screenshots maken we gebruik van <a href="https://chrome.google.com/webstore/detail/postman-rest-client-packa/fhbjgbiflinjbdggehcddcbncdddomop" target="_blank">Postman</a>. |
||||||
|
|
||||||
|
We moeten de volgende parameters meesturen: (<a href="http://tools.ietf.org/html/rfc6749#section-4.1.3" target="_blank">documentatie</a>) |
||||||
|
|
||||||
|
<ul> |
||||||
|
<li><b>grant_type</b>: Moet de waarde "authorization_code" hebben.</li> |
||||||
|
<li><b>code</b>: De autorisatie code die we hebben gekregen van de autorisatie endpoint.</li> |
||||||
|
|
||||||
|
<figure> |
||||||
|
<img src="static/img/oauth_get_token.png" style="width: 50%"> |
||||||
|
</figure> |
||||||
|
|
||||||
|
... Wissel om voor een access token (binnen 60 sec!) ... |
||||||
|
|
||||||
|
Welke access_token heb je gekregen? <input></input> 2 punten |
||||||
|
En welke refresh_token? <input></input> 2 punten |
||||||
|
|
||||||
|
Gebruik de access_token om de API /api/hello aan te roepen. |
||||||
|
|
||||||
|
Welke geheime code is er op de API te downloaden? <input></input> 5 punten |
||||||
|
|
||||||
|
... Refresh ... |
||||||
|
|
||||||
|
<h3>Google</h3> |
||||||
|
|
||||||
|
Calendar API: https://www.googleapis.com/calendar/v3/calendars/secavans@gmail.com/events |
||||||
|
Refresh token: 1/Capy9gSUUiS3HEWDCrc8AQjSoBg3uPz79JtOvSVw5kk |
||||||
|
|
||||||
|
... Wat is de geheime code? <input></input> 20 punten |
||||||
|
|
||||||
|
|
||||||
|
Gebruik je eigen Google account om iets uit een Google API te halen. Denk bijvoorbeeld aan je laatst ontvangen gmail mailtje, een overzicht van bestanden op Google Drive, |
||||||
|
|
||||||
|
Beschrijf alle GET en POST requests die je hebt gedaan om tot de .<input></input> |
||||||
|
|
||||||
|
<h3>Eigen API</h3> |
||||||
|
|
||||||
|
Maak een kleine webapplicatie waarmee je alle evenementen op je Google calendar kan inzien. Je mag hierbij gebruik maken van een framework. |
||||||
|
<input></input> 30 punten |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %} |
Loading…
Reference in new issue