Oauth and Security
OAuth has become standard practice for APIs https://tools.ietf.org/html/draft-ietf-oauth-v2-31
It security is based on the access token. Even if the communication between the authorization server and the resource server is done over SSL, they are still risks that someone can have access to the access token (could be accessible on client side, localStorage, cookie or event server log file ...).
By having a short lived access token, a compromised access token would limit the time an attacker would have access. Refresh token mitigates the risk of a long-lived access token leaking. Using refresh token, we can use a short lifetime for our access token, and use it to renew it.
If an attacker was able to get the refresh token they'd be able to get more access tokens at will until such time as the OAuth server revoked the authorization of the client.
The RFC differentiate 2 types of clients: ones which are considered as confidential, and the others.
Requesting our access token from username password
OAuth2 provides a "password" grant type which can be used to exchange a username/password for an access token. For example, the native Twitter app could use this grant type to log in on mobile or desktop apps.
Note: Since this obviously requires the application to collect the user's password, it should only be used by apps created by the service itself.
Note: the client secret is not included here under the assumption that most of the use cases for password grants will be mobile or desktop apps, where the secret cannot be protected.
At this time, the oauth2 server will respond with the access token and refresh token. We will see below how we can securely store the refresh token in our app. For now, let's first deal with the access token, to automatically add it to all requests.
Adding access token to all requests
You can either add the access token as a query param or http header. I would recommend using http header because it has 2 main advantages:
- there is no risk that your access token will be stored in a log file on the server.
- it's better to have a "clean" url
Adding Access Token to HTTP Header
Lets add the code to add the header authentication to all requests inside the run block (a run block is the code which needs to run to kickstart the application).
Now our access token is automically added to all requests.
Using Refresh Token
One solution I have successfully used is to encrypt the refresh token and set it in a cookie (on the server side). Once the client will try to renew the access_token, the server will receive the encrypted cookie it created before. After decrypted it, you can use it on the server side to request a new access token and finally returns the new access token in the response.
Use Angular Http Interceptor to automatically renew the access token
We can use a angular response interceptor ($http interceptor) to automatically call our resource server to renew the access token when a 401 request is catched.
Your code may looks like:
Note: The encrypted refresh token will be automically sent with the request. You will have to decrypt it and pass it to the resource server to renew the access token.
The problem with this interceptor is if the client start doing multiples async requests, it will end up doing multiples call to renew the token and the last call will invalidate the previous ones. We need to store all failed calls in a queue and then retry all the requests previously failed due to HTTP 401 response when we will get the new access token.
This is exactly what this lib is doing.
Its storing all failed (401) requests in a queue, and retry all of them when we are succesfully renewed our access_token (by calling authService.loginConfirmed()).
Our code now looks like:
For the renew token, storing it in a encrypted cookie is a working solution ; be carefull of XSS attack (someone could steal the encrypted cookie) and use a proper encryption algorithm if you go with it.