1

I have recently started on a project involving a REST API. The API requires authentication with requirements for administrators to be able to view logged in users and to be able to revoke specific login-sessions immediately. The API is consumed primarily by a SPA and a native application.

During my search for existing implementations in ASP.NET Core 2x I am however having some trouble. It seems there are 4 main methods of authentication:

  1. Cookie-based
  2. JSON Web Tokens
  3. OAuth 1 and 2
  4. 3rd party services such as Microsoft, Google, Twitter etc.

Due to the API being consumed by a native application cookie based authentication isn't viable. There is no requirement for integration with 3rd parties (such as Google), so that isn't an option either. Much like in the same way there is no requirement for the API to be consumed by an unknown number of 3rd party applications, which effectively rules out OAuth.

Now I am left with JSON Web Tokens, but... They also have issues. Mainly the requirement of immediate revocation of logins is important, however, this is not possible when using JWTs. A possible solution is maintaining a revocation list, but that defeats their stateless nature as each request to the API would need to check this list. But as this is not a large-scale application the stateless feature is unimportant at the moment. I can't use tokens with a short lifetime either as the requirement for immediate revocation doesn't work well with this. Here is an article, which perfectly explains my issues with JWTs as sessions.

So now we are at the big problem. There are no existing solutions supported out of the box in ASP.NET Core available.

Question 1: Any alternatives or remarks of the previously mentioned issues, which would change the conclusion?

I have searched the vast space that is the internet for anything, which would meet the requirements, but is unable to find anything else, but JWTs and OAuth... Everyone uses JWTs for everything it seems. So this has led me to what I feared: I need to write my own implementation :(

The optimal solution would be:

  1. The client exchanges username/password for a random token
  2. The client sends the token in the Authorization HTTP header much like JWT may do.
  3. The token is used to fetch the user's AuthenticationTicket upon an incoming request and the token is verified.
  4. Logouts or revocation removes the token (and effectively the AuthenticationTicket) in a centralized store

Looking through the source code for the existing solutions for mainly JWT and Cookie authentication in ASP.NET Core I realize I can reuse quite a bit of the existing implementations and integrate well with the framwork, but I would rather avoid writing anything security related myself.

Question 2: Anyone know an implementation, which satisfies this flow or can be configured to?

As a closing note. I know storing session state server-side is against pure REST principles, but I find this far more practical given the requirements. To overcome any scaling issues over a small number of containers I plan to use a centralized server (redis as an example) as cache/storage, which should be more than enough to handle the expected traffic several times over.

  • Have you considered the option of client-certificates? A cursory search tells me this is supported: stackoverflow.com/questions/14933477/… – JimmyJames Jul 30 '18 at 21:03
  • @JimmyJames I haven't seen client certificates used like this before and it is indeed an interesting method. However, I think that giving the client responsibility for handling certificates is too far away from the solution I am aiming for. – AnotherGuy Jul 30 '18 at 21:19
  • "No requirements" doesn't mean "No possibility". So what if you don't need multiple apps, doesn't mean you can't use OAuth if for some reason you like it. So what you don't need to integrate 3rd party services, doesn't mean you can't, if authorizing thorugh google would otherwise work for you. – Misamoto Aug 6 '18 at 12:29
  • Have you considered Bearer auth? tools.ietf.org/html/rfc6750 – Nicholas Shanks Aug 12 '18 at 15:50
1
+50

Question 1: Any alternatives or remarks of the previously mentioned issues, which would change the conclusion?

Cookies are just headers, your native client can add and read them them no problem. Not sure if the built in solution allows revocation though.

JWT/OAuth The reason revocation isnt supported is to enable to idea that resources can validate the request without contacting a central server. Avoiding that bottleneck

However! any solution with immediate revocation will require that you validate on a central server.

Implementing this extra check is simple. eg with the IdentityModel nuget

public class MyJwtSecurityTokenHandler : System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler
{
    public override ClaimsPrincipal ValidateToken(string token, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
    {
       return  myAuthService.ValidateToken(token, validationParameters, out validatedToken);
    }
}

The auth server can keep track of issued tokens, expose a revoke endpoint and a LoggedInUsers endpoint. Just like the old MembershipProvider...

Question 2: Anyone know an implementation, which satisfies this flow or can be configured to?

You want an out of the box solution, MembershipProvider and getting your native client to understand cookies is probably the closest you will get. You could go for the Cookieless option, but having the token in the url is considered less secure and its probably hard to handle on the client anyway.

But with .net Core, I'm unsure that it fulfils all your goals, and it's definitely swimming against the tide of JWT tokens with claims.

I would go with OAuth and JWT and program the revocation custom extras myself. Ensuring that I do validate the JWT normally as well as checking for revocation.

I would expect the requirement for logged in users and revocation to eventually be dropped and this would allow me to simply remove it.

In Fact, lets move the logged in users right out to a reporting component rather than auth, we can get better stats that way anyway

  • Thanks for the answer. I am curious as to why you would expect the requirement for revocation to be dropped? This does seem pretty basic if you want to support any kind of logout feature or give your administrators the possibility for handling unexpected abuse by previously authenticated users. Without it both actions seem next to impossible to handle. – AnotherGuy Aug 2 '18 at 15:03
  • Just because I've been in the same situation a few times. People who are used to the old style of session based website ask for logged in users and logout buttons because that's what they expect to need for 'security'. But all modern apps and websites use a long RefreshToken + short AccessToken and the user experience reflects that. At some point they ask "why isnt our app like facebook?" or whatever and you flip to that approach – Ewan Aug 2 '18 at 15:08
  • So what you describe is practically OAuth, right? When I know for certain the API is consumed by two known clients and tailored to them I find the usage of OAuth misused. In regards to short lived tokens. Balancing the lifetime of the token vs auth-server load is hard. And having a too high lifetime increases the window of opportunity greatly. Having a too low affect user experience and auth server load. All in all suboptimal for this project in my mind. Am I completely off here? – AnotherGuy Aug 2 '18 at 15:16
  • Are you arguing that OAuth is insecure? I'm pretty ambivalent on the subject tbh, but the argument is, say you spot a malicious user and want to block them your time to block is time to notice + time to login and click ban button + access token expiry. if you are relying on humans to notice things then the extra 5min for token expiry wont make a difference – Ewan Aug 2 '18 at 15:39
0

Not really an answer but too long for a comment.

Are you absolutely sure your native client does not support cookies? The article mentions that most good client libraries do support them.

As for JWT: marry them to your idea. Get that extra random ID as a field in the JWT. Or maintain a revocation list based on the tokens' signature (which should unique after all)

  • Can you comment a link to the article you mentioned in the answer? I cannot seem to find it ;) – AnotherGuy Jul 31 '18 at 11:56
  • The one linked in the first sentence of the article you linked in your question. – Jan Dorniak Jul 31 '18 at 12:34
  • I have previously looked into this solution and decided to give it another try. However, I have come to the conclusion that it is suboptimal (my opinion). I lose the stateless nature of JWT and take a performance hit of having to verify HMAC signatures on each request in addition to a back-channel request for the storage impl. This combined with the fact, that this doesn't solve the requirement of being able to see currently logged in users means I am very hesitant to use this :D – AnotherGuy Jul 31 '18 at 18:31
  • Shouldn't AES-NI negate much of the performance hit? And yes, the requirement to view currently logged in users basically looks like sessions one way or the other. Also - what kind of app (Lang/lib) is it that it doesn't handle cookies? – Jan Dorniak Jul 31 '18 at 20:43

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.