2

We are building a mobile app that will use OAuth2 to authentication the users via the grant_type "password" (two-legged setup). So basically the user just sends the username and password, receives an access_token and a refresh_token.

The access token has a short lifetime and the refresh token is one-time use. So as soon as the access token expires, the user sends the refresh token to receive a new access and refresh token. So a pretty basic setup I guess...

However, we would also allow the user to authenticate via email, i.e. the user enters his email in the app and just click "send authentication email". He receives an email with an authentication link that opens the app and authenticate the user.

My idea is that the app generates a guid and sends that to the server. The server encodes the guid as a claim into a new refresh token which is then emailed to the user. The user clicks the link and uses the refresh token to receive a new access token and the user is the authenticated without having to enter any password.

I'm not that familiar with OAuth and security in general and we're using standard components to implement the authentication. So my question is:

Are there any security issues with this this approach?

  • If the reset tokens are single-use it's probably not too dangerous, but it seems silly. Even for a pretty good password, it's faster to enter it on a mobile device than it is to request and receive an email. For the record, the intended use of OAuth2 refresh tokens is for persistent access; an app gets a refresh token, and as long as it has a valid refresh token and the session is not invalidated on the server, the app is authenticated. The access token is short-lived but, if you're using refresh tokens at all, you expect the client to remain authenticated for a long time. – CBHacking Sep 30 '15 at 9:00
  • The reason for it is not because its faster, but because people tend to forget their password. Using email (or sms or similar) authentication is more and more adopted by different applications so its not a new thing. From a ux perspective, this is a much more convenient way than trying to get users to remember all passwords on their different services. – Bjorn Sep 30 '15 at 9:29
4

tl;dr

Are there security issues with your approach? Difficult to say, as it is not clear from the question which token you are sending in the mail. You should read my long answer to understand my concerns. But, in short: if you send the guid, then yes, there is an issue (see the 'implementation' part of my answer. If, on the other hand, you send the refresh token: then there probably is no security issue.


Preface

As pointed out by @CBHacking:

the intended use of OAuth2 refresh tokens is for persistent access; an app gets a refresh token, and as long as it has a valid refresh token and the session is not invalidated on the server, the app is authenticated. The access token is short-lived but, if you're using refresh tokens at all, you expect the client to remain authenticated for a long time

Anyway, it does not really matter. If you want to use the refresh token only once, then you are free to do so.

An example of the implementation you want to achieve

I'm not sure if you already know it, but Slack has actually the sign-in experience that you are describing. You can test it yourself by creating an account and install their mobile app, or just see how it works here. Their link looks like this: https://slack.com/z-app-0000000000-0000000000-AAAAAAAAAA (I've replaced numbers with 0's and letters with A's). I assume that their link is built-up as follows (note: I don't know if this is true, it's an assumption):

  • First part: user id
  • Second part: time
  • Third part: unique token

Clicking this link will redirect you to somewhere like this: slack://login/XXXXXXXXX/xoxo-0000000000-24characterlongtoken

So, another token is created which is then used to open the application.

Implementation

Your guid implementation seems a bit overengineered for the following reasons:

  • Why make use of an app-generated guid, if you could just as well directly send a 'magic link' to the mailaddress of the user from the server? Your security lies with the security of the user's access to the mailbox, not with the guid (which is not secure anyway). I agree that you need some kind of token, more about that later.
  • You mention that this guid is then encoded in the refreshtoken as a claim. I assume you mean adding it to the protectedticket of the user (the refreshtoken itself does not contain claims, in contrast to the access token).
  • And then, I am a bit lost in your implementation. You mention that you send the refresh token to the user, but really a refresh token is only a reference to a protected ticket in your database. So you then use this refresh token to retrieve the guid. And then what? You see, the guid is of no use in this set-up. The only token that matters in this set-up is the refresh token.

Just send a token

Sidenote, I make use of the following notations:

  • access token: the access token as described by oauth
  • refresh token: the refresh token as described by oauth
  • unique token: any token that is unique. If you want to use the refresh token for this, it's your choice. I give other options at the end of this answer.

So, you actually provided your own answer. We get rid of the guid and do it as follows:

  • The user requests a magic link on the application.
  • On the server, you check if the emailaddress is known, if so, create a unique token for this user and send it in a mail (link to an endpoint that can verify the unique token). You probably also should send some kind of user identifier.
  • When the user clicks the link, you verify the unique token (for that user) and issue a new access token and refresh token.

Now, as mentioned before, a refresh token really is considered a long-lived token. In some implementations, this token even never expires. To prevent access, you should revoke it instead. Therefore, it does not really make sense that you would use a refresh token as a unique token in the email.

Even better would be to create a unique token that is uniquely tied to the user. This depends on your implementation, but in .NET you could for example use GenerateUserTokenAsync. When using this, you don't even need to store the token in database, when the login request comes in, you can just call VerifyUserTokenAsync and you are sure that the user is the person you sent the mail to.

If you want to create a custom unique token instead, you should of course link it somehow to your user in the database. You could generate such a cryptographically secure unique token yourself. Depending on your programming language, the implementation differs. Google for it, and you will get answers.

  • Thanks for a great answer! I'm feeling more comfortable with the solution now, at least there is no evident flaw in the setup. You are right about the using the token, when looking at our proposed solution, the token we send is actually not a real refresh_token but more like an access_token, I'm merely creating an "AuthenticationTicket" (using microsoft's oauth library) an serializes it. – Bjorn Oct 1 '15 at 11:41
  • The idea behind the GUID is that the client generates it, sends it to the server when requesting an email. The GUID is then encoded into the token and when the client tries to use the authentication link, it also sends the GUID so that the server can confirm that it is the same client that requested the mail that also uses the mail. The reason behind this is to avoid someone from stealing the mail on the way. They need the GUID as well which is only known by the client. – Bjorn Oct 1 '15 at 11:47
  • Regarding the refresh_token and one-time-use. I have merely based my solution on this tutorial, so I haven't giving it too much thought bitoftech.net/2014/07/16/… The author has a discussion in the comments regarding why he used one-time-use refresh tokens. – Bjorn Oct 1 '15 at 11:56
  • @Bjorn, regarding the GUID, it is created and stored on the client you mean? So an authentication link will only work if 1. the mail is received and 2. if the link is opened on the same client (eg iphone app) where it was requested? – Michael Oct 1 '15 at 17:39
  • @Bjorn, I do like the blogpost you are refereing to. It's certainly a good start. However, his advice concerning refresh tokens is a little rough. You should try to take a look how trustworthy implementers do it (e.g. Google). In this stackoverflow post, it is mentioned that you can just have 25 refreshtokens per user/client combination (so they could have 25 browsers open). From the moment the 26th is issued, the first one will be invalidated. No need to store browser_id or whatsoever.. – Michael Oct 1 '15 at 17:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.