Should I use Identity Server 4 for a single SPA client? - asp.net-core

I have been deeply studying everything I have been able to get my hands on regarding Identity Server 4. In an application I am working on the architecture of I will have an API and a React SPA.
In the past I would have just used JWT Authentication and called it a day, but I noticed that providing an SPA with a refresh token is a bad idea for security reasons. From my research I have been able to see that what fits my situation the best is to use Authorization Code Flow with PKCE enabled.
However, I don't have an SSO type of situation and I just want to have a single API, rather than an Authorization API and an application API, I am wondering if I should really use Identity Server at all. While Identity Server is powerful it seems rather overkill for my situation.
My only problem with my previous auth flow is the refresh token and keeping it secure. Is there a proper way to keep the refresh token secure in an SPA or is there another method I could use to mitigate the security flaw that is to store my refresh token in local storage or a cookie?

Related

What are the benefits of implementing OAuth (JWT access tokens with refresh tokens)

Current Setup
I'm currently building an application, and have just finished implementing an OAuth authentication server. This is my first "real" attempt at a project that has a legitimate user authentication and management component, so much of this is new to me.
I've implemented the OAuth specification. This means the following:
The authentication is deployed on a separate webserver with a separate DB than the application server.
The auth server logs in a user, and issues them two tokens. One is a JWT access token that contains information about their user identity. This has a short-lived 15 minutes expiry. The second token is a refresh-token. This is a single-use token with a 7 day expiry. It is used to fetch another access token with the application server returns a 401 (the access token has expired).
The application server shares a secret key with the auth server, and has middleware that verifies the JWT access token.
Concerns
My concern is that I've over-engineered a project that didn't need this much complexity. Since the auth/app are distinct, this means that my client code needs to be aware of, and handle refresh token rotation. It needs to interpret 401s, and fetch another access token.
As far as I can tell from my reading, this wouldn't be necessary with simple session cookies that persist. The cookie is just included in requests to my domain. If I killed this approach, and just had my server do a DB lookup on a signed session cookie - I would avoid a lot of this client complexity.
One consideration is that I’m using a React SPA frontend client. This is also new territory for me, so I’m not sure whether or not this changes the situation.
As I said above, I'm new to a lot of this so could use some advice from people who have worked in this space for longer and have the experience. Is OAuth worth the hassle?
Options
OAuth with access tokens (JWTs) and refresh tokens:
Pros: Provides a secure and scalable way to handle user sessions.
Cons: Client needs to be aware of refresh token rotation procedure and handle 401 responses by using the refresh token to request a new access token, which can add complexity to the client-side code. Also adds complexity (and cost) to the AWS infra stuff. I need to know how to get the auth server and app server on the same base URI. Also makes my local dev environment a little more involved.
Server-side sessions using signed cookies:
Pros: Simpler for the client, as it does not need to handle refresh tokens or 401 responses.
Cons: Server needs to manage session state, which can be more resource-intensive. This means a DB call on every request.

Questions about Native applications and openId Authorization code flow

I have a few concerns with an OpenId Connect strategy that I would like to use and have been unable to find specifics on what the security concerns may be and any glaring issues with it I am overlooking.
Currently, I have an OpenId Connect implementation using Openiddict with Authorization Code flow. For the client, I have a React-Native app using react-native-app-auth.
I see from other questions on SO and from issues posted on the Openiddict repo that the recommended approach to third-party providers (e.g. Google) is: Client -> Auth server -> Google Auth -> Auth server -> Client/Auth server code and token exchange
However, it seems that a better approach from a UX standpoint (when using a SPA or native app) would be to implement something similar to GoogleSignIn on the client and either handle the identity on the server using an IdToken or authorization code from Google. This introduces an issue as the flow previously recommended could not be used as the entire initial challenge and redirect from Auth server to Google Auth has been skipped.
I have seen that this issue is mitigated by not using the authorization code grant and instead implementing a custom assertion grant. This seems to be an alright approach but would require exposing a custom grant and handling the flow differently on the client and server for local and third-party logins.
My proposed solution continues to use the authorization code flow and instead of adding a custom grant type the client could just pass a third-party identifier "Google" and the token or authorization code in the additional parameters of the OIDC authorize request. The authorize endpoint could then detect the provider and token, perform token validation, create a user or principal from it, and create an authorization code to send back to the client for the code/token exchange. This flow would look like the following:
1. Get the id token from the provider Client -> GoogleSignIn -> Client
2. Pass token to auth server and initiate code / token exchange Client -> Auth Server -> Auth server Verify Google IdToken (JWKS, issuer, audience, provider specific validation, etc...) or exchange auth code -> Auth server -> Client/Auth server code and token exchange
One downside to this approach would be the additional hops to verify the token on the server side. If the token was returned from GoogleSignIn, they themselves said that it could be trusted. https://developers.google.com/identity/protocols/oauth2/openid-connect#obtainuserinfo
I see that it is generally recommended to place the auth server between the client and the third-party but in this process the server is still between the client and auth server but only after the initial exchange from the client and third-party.
Questions,
In general am I missing something with this flow?
In this case would it be necessary to verify the token on the server side?
Is there some better way to approach this that I have completely overlooked?
Am I making this too complicated and UX should not be this much of a concern?
Instead of adding the provider and token to the additional parameters would it make more sense to pass it in the body of a post request? I don't see the issue with passing it via query string but that's also part of the reasoning for the authorization code grant from my understanding.
Apologies in advance for anything I have missed or omitted for brevity that should have been included.
Thanks.
ARCHITECTURE
I'm not sure I understand the UX problem - your existing architecture feels really good. If you want to login directly to Google, just send an acr_values=google query parameter in the authorization redirect, to bypass any authentication selection screens. The exact value will depend on how Openiddict represents the Google authentication option, and some providers use a non-standard parameter such as idp. Have a closer look at the OIDC request parameters.
A key OAuth goal is that the Authorization Server (AS) - Openiddict in your case - shields your apps from all of the provider differences and deals with their nuances and vendor specific behaviour. Your apps then also only receive one type of token, and only ever use simple code. As an example, the Curity AS supports all of these options, none of which requires any code in applications.
APPAUTH AND UX
If a user is already signed in then it can, as you say, look unnatural to spin up the system browser and them it is dismissed immediately.
A common option is to show the consent screen or an interstitial page to keep the user informed - and the user clicks one extra button. This can also be useful for getting password autofill to work. My code example and blog post shows how this might look, though of course you can improve on my basic UX.
OFFLINE ACCESS
I find this term misleading, since refresh tokens are most commonly used when the user is there. Are you just asking how to deal with tokens in a mobile client? Aim for behaviour like this:
Standard messages for API calls with access tokens in an authorization bearer header
Standard refresh token grant messages to refresh access tokens - eg as in this code
Note also that mobile apps can save tokens to encrypted secure mobile storage that is private to the app. This can improve usability, eg by avoiding logins every time the app is restarted. You should think through scenarios such as stolen devices and token lifetimes though.

ASP .NET Core Identity default authentication vs JWT authentication

I am developing ASP NET Core Web API and I am confused by choosing the authentication method. I used to apply default Asp Net Identity authentication, but recently I've known about JWT. So I've implemented Authentication almost as it done in this article: https://stormpath.com/blog/token-authentication-asp-net-core.
But I can't understand the benefits of this JWT. With simple Asp Net Identity Authentication, I don't care about token storage etc. I only need to log in with signInManager and use authorized methods until logout. With JWT I need to think about the token store, expiration, and other difficulties. So, what're the benefits of this JWT? How can I store this JWT token after login? Furthermore, should I even use this JWT? In my case, I need simple authentication for simple WebApi which will be used by one or little bit more users. I've also heard about OpenIddict, Auth0, IdentityServer, so what's the difference between all of these authentication mechanisms?
This is the way I understand this, split in to 3 logical parts.
Authentication Server - this will authenticate and issue the JWT token, when the API need's to validate the token it will send the token to this server to validate it.
Client - this is what serves your web pages, or you app perhaps. This is what will need to request and store the the JWT token. The client will need to pass the token to the api every time it requests data.
API - this is what serves the information and needs to validate the token with the Authentication Server.
So, what're the benefits of this JWT?
JWT is issued to the client and stored on the client side. Having JWT allows multiple client's (App's or Websites) use the same authentication server which distributes JWT and states which API's the client's can use and how.
How can I store this JWT token after login?
I only tried to store it in an Ionic 2 app which uses angular 2 which has a storage module. But i'm pretty sure numerous people have done this already and asked this question:
Simple JWT authentication in ASP.NET Core 1.0 Web API
Token Based Authentication in ASP.NET Core (refreshed)
Update
If your front end is made purely html/js/css and doesn't have a back end to accommodate it you would store your token in local storage, there a multiple npm packages that help you with this like this one. You want to look for Implicit flow.
Otherwise if you do have a back end that comes with your front end you want to store the token in a session/database your pick, there are 3rd party providers to do this like IdentityServer4. You want to use Hybrid flow
Furthermore, should I even use this JWT? In my case, I need simple
authentication for simple WebApi which will be used by one or little
bit more users.
The reason for the whole separation of concerns is performance so you don't really need it since it's just one or a little more users. Do it because it's a learning experience, JWT is not easy to setup from the beginning and will require you to do a lot of reading and you will fail and you will be frustrated but at the end you will know how to set it up and how it works
I've also heard about OpenIddict, Auth0, IdentityServer, so what's the difference between all of these authentication mechanisms?
So what you did in the Stormpath tutorial is NOT production ready. That is just a little demo, to help you understand what JWT is and how it works. The above mentioned are complete libraries that tackle all the heavy lifting and do not require you to built the whole thing from scratch. And the main difference between them is the scope that they cover.
I personally used IS4 and it had me crying no more than 2 times (It was simpler than I thought):
http://identityserver4.readthedocs.io/en/release/
https://github.com/openiddict/openiddict-core
https://auth0.com/docs/quickstart/webapp/aspnet-core/00-intro
Use tokens (JWT) if you have multiple applications or services (web, mobile, other services) connection to your API. Benefits: Stateless, Scalability, No cookie, no CORS problems (if you allow it).
If your API will be used by only one web application use the default ASP default authentication system. Its easier to set up.
If you webapi and user interface are hosted in the same web application, token bases security does not buy you anything over the cookie based authentication provided by the built in authentication. That's because the authentication cookie gets sent back to the keep application on every HTTP request. When you make calls to a website other than the one you signed in on those cookies do not get sent. So JSON Web Tokens (JWT) provide a standard format for browser to send identity information to a website when a cookie isn't an option.
If your Web Api is to be accessed by AJAX calls then JWT may be a desired choice, but not mandatory. judging by the description of your app,it seems to me that the default authentication system can serve you well.
Auth2 is the authentication mechanism that enable external login such as Facebook. It is part of the default authentication system, and you need not do much in order to employ it in your app.
OpenIddict sits on top of Auth2. It is part of the default authentication system, and you need not do much in order to employ it in your app. It is the authentication mechanism that enable external login such as Google+
IdentityServer may be used for large Wep Api that is accessed by Ajax calls. As for instance, you can use IdentityServer to authenticate users longing to a front end Angular app.
Once again, the default authentication system can serve you well.
Hope this helps...

Using IdentityServer vs creating custom JWT based authentication

Authentication is a bit over the top for me.
My understanding is:
Client performs the login
API or authentication server responds with a token
Client calls API (includes a header which holds the token)
API checks if the token is valid and if valid responds with a resource
I checked several options:
IdentityServer4
Has the advantage to easily implement 3rd party authentication like Facebook. You can easily use the ASP.NET Core identities to authorize your API based on roles.
Custom (simple) JWT authentication
Reference: ASP.NET Core Token Authentication Guide
With this approach, you have to make your own identity user and fetch it from a database.
Cookie authentication
The client holds the token in a cookie when sending a request you have to send it too.
My front-end is written in JS and back-end is ASP.NET Core, so it's CORS.
I don't know what should I use and why? Why do many recommend to use IdentityServer4; isn't the simple custom authentication enough?
(I have problems with the IdentityUser properties and the "hidden" database checks)
The problem with authentication is that it may be simple to write a few lines of code that accomplish the end goal of authenticating your users, but it's really complex to do so in a way that you won't regret it later; aka my application got owned.
One of the steps to take to try to prevent that from happening is don't try to reinvent the wheel and stick to using current standards. However, even with standards, you need to implement them accordingly and that is why you probably see recommendations like the one you mentioned. I would actually make the same type of recommendation my self, delegate as much as you can to third-party libraries like IdentityServer4 or cloud services like Auth0. (you should know I work at Auth0, so you can consider me biased; however, for a non-biased recommendation you can check ThoughtWorks Technology Radar).
Also, if you store tokens in cookies, although the storage and transmission of the token happen differently this is still a token based-authentication system; for more on the possible implications of choosing a client-side token storage approach check where to save a JWT in a browser-based application.
In relation to CORS, you did not make that explicit, so I thought it may be worthwhile to mention it. You only need to actually worry about CORS if you deploy your front-end and back-end in separate domains because even if development happens in isolation if they share a domain CORS is one less thing you need to worry about.
Conclusion
For a front-end browser-based application talking with a REST API, the most common approach is to go with token-based authentication that relies on OAuth 2.0 protocol to perform the actual issuance of the tokens. Additionally, you should aim to delegate token issuance to a third-party (IdentityServer4 or other) so that you don't need to implement or maintain that part of the system and only need to consume/validate the generated tokens.

MVC AD Azure Refresh Token via ADAL JavaScript Ajax and KnockoutJs

There is an inherent design flaw in the type of MVC application I have built and I believe I'm not the first to realize.
I have an MVC 4 Application that utilises AD Azure Authentication that was introduced to the application in the following way
Developing ASP.NET Apps with Azure Active Directory
Once as User is Authenticated and Home.cshtml loads, KnockoutJs is used to perform JavaScript AJAX POST and GET requests to read and write data.
So not exactly a Single Page App, but rather, a mix of traditional postbacks for Authentication and Serving Assets and Read/Write operations through AJAX.
During AJAX requests, the authentication token expires and AD is not able to refresh the token through JavaScript.
The following browser error is observed
XMLHttpRequest cannot load https://login.windows.net/xxx.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'xxx' is therefore not allowed access.
I have researched adal.js and the following posts but not sure if adal.js is the solution to my type of application
or how best to incorporate it to make it work with my type of application.
My understanding so far:
I am not using AngularJS.
I do not start out authenticating via JavaScript and I my authentication is not JavaScript driven to be able to benefit from adal.js.
Authentication is done server-side and the subsequent OAuth2 refresh token mechanism requires full page postbacks.
I've stumbled on various releated posts by Vittorio Bertocci but none address the particularities of this type of MVC application design.
ADAL, Windows Azure AD and Multi-Resource Refresh Tokens
WAAD doesn't refresh access token from javascript
Combining ADAL.Net and ADAL.js
AngularJS + ADAL.JS set Resource ID (Audience)
The issue with your setup is that you are using cookies for authenticating AJAX calls. Cookies aren't really well suited for that, and the limits of the approach typically emerge when you need to make calls outside of your domain and/or when the cookie expires. The fact that it is a common approach, largely as an evolutionary step due to the fact that proper SPA support for auth wasn't available for some time, does not make it a good approach.
You are free to stick with your current approach, but that will cause some pain. There is no established mechanism for triggering a session cookie renew from JS. Although that can be hacked together, we don't have samples for that - mostly because it's a hack :) the basic case seems easy enough, but as soon as you start considering all possible cases (what happens if while your app session expired, the user signed out of Azure AD and signed in with a different account?).
The most foolproof approach would be to abandon the hybrid approach. If you want to be a JS app, you can eliminate all the server-driven login do so and still retain the ability of doing server side flows (via onbehalf of grants, like https://github.com/AzureADSamples/WebAPI-OnBehalfOf-DotNet). You don;t even need to convert to angular if you don't want to, see https://github.com/AzureADSamples/SinglePageApp-jQuery-DotNet.
And if you want to be a postback based app, you can drop the JS part (though that sounds painful).
TL;DR: securing AJAX calls via cookies is not a clean solution and you are bound to feel some pain. Your choices are between patching the issues with ad hoc hacks, or refactor toward a more canonical approach. Sorry for the bad news :(