Simple story behind Refresh and Access tokens

    Nowadays security schema that lays on two tokens quite common. There are a lot of information about theme in the Internet. There are often only description what is Refresh and Access tokens and how to usem.


    To understand concept behind tokens I would like to do one simple thought experiment.


    Let’s imagine that you are a student that likes money but often has around zero on his account balance.


    On the way to your university you open your bank mobile application to check your account balance.


    To show you a balance application needs to execute request to the bank server:


    GET http://api.mybank.com/balance HTTP 1.1
    and receives response


    { balance: '$0.0' }


    image


    Would be good if no one except you could check your bank account. To do so, let’s add special header with user name and your unique password:


    `Authorization: Username Password


    Authorization: JohnDwayson QWERTY1`


    Now server can authenticate you by your personal username and password. It means that pair JohnDwayson QWERTY1 needs to be kept in a secret place on your mobile phone to be protected from someone who not allowed to spend your money. Would even better if we could avoid storing password but no one wants to enter it too often.


    When we are using our mobile application for the 30 minutes in a bus, it will send your password over network many times in 30 minutes.


    image


    Every requset contains password
    Let’s continue our thought experiment. You are still in a bus and your app sends request to the server.


    What if a fraud is sitting around you in a bus and he can intercept one or few http packets from your mobile phone to the bank server?


    If app updates information every minute, fraud will have 30 possibilities to intersect requests and get your password.


    Let’s assume he stole 5–6 messages. Your password now is compromised and fraud can use it to access your account information.


    image


    Man in the middle can overhear the password
    What can he do with this information? Good news that he cannot spend your money as you don’t have it … yet :) He also cannot change your password as in this case you will notice that and can use SMS from a bank to recover the password. Old stolen password in this case will no longer be valid and student will save his money


    But what he can do is to keep checking your balance in parallel with you. He can easily write a Python script that will check your account every 10 seconds and as soon as you will receive money he can spend every single cent for buying bitcoins. Probably even worse case if his script will spend 5–10 buks every day, and it is likely will not be noticed for the months or years.


    image


    Hacker waits for your money
    To avoid this, we can ask user to change his password after some time. Let’s say password will be valid on for 3 months. Good thing is that after 3 month he will lose access to your account. Bad thing is that he will lose access to your account only after 3 months. Obviously, to avoid this we can ask you to change your password every month or week. But it can be annoying for the end users.


    Would be good if we will not use our password too often in our requests. To do so we can introduce special endpoint: http://api.mybank.com/login. We are going to send our credentials only to this endpoint and in return server will generate for us special token. Let it be just unique string, GUID, that server stores in his database. Let’s call this unique string is Access token. We will use it instead of our username and password in header of every request talk with server. Similar to password let’s set expiration time for the access token.


    image


    To update balance we don’t need a password
    Let’s reproduce our thought experiment.


    We are in the bus and someone stole our http request to check balance. But now fraud has access token only.


    image


    It’s not enough to steal only access token
    What hacker can do now with this information? First of all, he still cannot spend your money. Second is he cannot change password as simply he doesn’t know it. Also, now the expiration time for the password and access token is two separate settings. We can leave password expiration time as 3 months and we need to choose access token expiration. We would like to set this time as short as possible, because to get new access token we cannot use token itself. If someone will steal this token he will able to renew it as long as he wants.


    When access token is expired, to get a new one we need to send user credentials again. If you are in a bus for the 30 minutes and your expiration time for the access token is 15 minutes you need to send your password at least 2 times. Usually we want to update access token earlier, let’s say every 10 minutes, otherwise user may notice some delays to obtain new token. Also, it solves issue when few requests at the same time are failed because of the expired token and we need to retry them in a right order after obtaining new token.


    Now results are better. Fraud has access to our data only for the 10 minutes instead of 3 months. But he still has good change to steal our password and we may not notice this until he steals our money.


    The issue now is to obtain access token we still need the password. What if we will generate one more unique string. A special token used just to obtain access token.


    To achieve this our login endpoint should accept username and password and returns new token called Refresh token. Which we will store in our mobile app. Refresh token can have longer expiration time, for example a month.


    image


    Renew flow for refresh and access tokens
    Every time we need to renew access token we need to send just refresh token. So our password will be sent to the server only once in a month or ever more rarely. Basically we just need password only to retrieve first Refresh token.


    We still need access token to execute requests to obtain some data from the server. So:


    POST /login with username and password returns us refresh token
    POST /renew with refresh token returns us access token
    POST /balance with access token returns us actual balance


    Let’s replay our experiment again.


    We are in a bus. Our student is checking his balance.


    But now our application uses refresh token that stored somewhere in a file on mobile phone.


    Application is sending requests like:


    POST /renew
    GET /balance
    GET /balance
    GET /balance
    POST /renew
    GET /balance
    GET /balance
    GET /balance


    As earlier, hacker is intersected few requests with access token in a bus.


    As expiration time for the access token is 15 minutes and we are updating tokens every 10 minutes.


    Hacker can use stolen information only for 10 minutes or less.


    What if he intersected one of the /renew requests and have refresh and access token? Theoretically he can use refresh token for a month to obtain new access tokens and still be able to stole money.


    But if we will regenerate both tokens on every /renew request and server stores only one refresh token at a time. Fraud’s copy of refresh token also became invalid in a 10minutes and he cannot use it without letting us know that token is compromised. If he will try to renew token, it will invalidate our token and we will be forced to relogin.


    One more advantage of refresh token is that we don’t need to store password in a application or browser and store only last refresh token instead.


    Interesting thing is that access token can be not just a random string, but can contain some useful information. For example, it can be expiration time, user ID and user role. In this case it is called self-contained token and server doesn’t need database access to validate token and user permissions. It can be very useful in microservices as it can increase performance and decrease coupling between microservices.


    It's a bit out of article theme but it is worth to mention scope.
    What if we will ask /renew endpoint only for access token that can be used exclusively for checking balance?
    If the user wants to spend some money he should receive additional different second token for that? We can call this parameter 'scope'.
    So we can ask to /renew?scope=[balance, news]. If our hacker stills this token he cannot use it to spend our money!


    Idea based on two tokens gives use better safety than just password or one token by design. In opposite of choosing longer password or stronger security algorithms.


    This was my explanation for basic concept behind tokens and how they work.


    On a practice there is a few different implementations of this concept that can be easily googled.


    Small note about flexibility in choosing an expiration time for the password and tokens.


    Typical expiration time can be:


    For the password it is 3–6 months. It is good to have this limitation. As databases can be stolen and user can reuse same password across services.


    For the refresh token expiration time can be about a week or month. For the people who is working in an office with some website it is useful to have this time at least longer than a weekend. Otherwise they need to enter password every Monday.


    Access token expiration time can be in a range from 10 to 60 minutes. Shorter time requires more requests for renewal but longer time can give more chances for the fraud.


    Conclusion:


    We need to use password to obtain long lived refresh token. Then send refresh token to obtain short lived access token. Than utilize access token to execute useful requests.

    Share post

    Similar posts

    Comments 3

      0
      Very informational. Keep it coming more.
        0
        That's all fine, but don't use a JWT with short TTL?
          0
          JSON Web Token is just an standard (RFC 7519) for creating access tokens to be URI/header safe and have possibiliity to contain some additional information.
          JWT quite often used as access tokens but you cannot replace whole schema based 2 (or 3 in case of auth_token, refresh and access token) with just one single token.
          It doesn't metter if single token is generated with JWT standart or just unique Guid. Single token concept is vulnerable by the reasons i tried to explain in article: To renew single token you need to use password. Than shorter time-to-live than more frequently you need to send passwords

        Only users with full accounts can post comments. Log in, please.