MVC AD Azure Refresh Token via ADAL JavaScript Ajax and KnockoutJs - asp.net-mvc-4

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 :(

Related

Using Microsoft.Identity.Web to authenticate users for WebApp+API, and how to manage lifecycle

I'm trying to create a webapp that uses multi-tenant Azure AD for authentication & authorization. I'm trying to follow the docs, using Microsoft.Identity.Web, and the pieces aren't clicking for me.
I've been able to successfully create a web app where users are able to login, get redirected back to my site, and get an id_token saved to their browser cookies so the web app is able to tell who they are. However, my web app also contains APIs itself, and it isn't clear to me how we're supposed to obtain an access_token, as well as manage the lifecycle by way of refresh_tokens, for calling APIs on the web app itself. In fact, refresh doesn't seem to be covered at all in the docs for Microsoft.Identity.Web.
Instead of the dedicated SDK, I've also tried using AddCookie()+AddOpenIdConnect() (the more generic solution). Using these middleware options I've successfully been able to obtain an id_token, access_token, and refresh_token. (Which seems to connect all the pieces of access, and refresh/lifecycle.) However, all of those tokens take up a fair amount of cookie space, and cause 431 Request Header Fields Too Large errors from Kestrel without customization.
It's clear that the intention is for access/refresh tokens to be stored server-side on some sort of in-memory or distributed cache. However, the documentation doesn't seem to outline how to deal with "web apps" that ALSO contain API controllers, and furthermore doesn't seem to outline how to deal with token refreshes in general.
Does anyone have any better in-code examples of how to configure a WebApp that authenticates users with Azure AD, and also properly handles refreshing the id/access tokens using the refresh_token?
Refresh tokens are automatically handled by MSAL.NET, which is used by Microsoft.Identity.Web.
We suggest you have a look at the following sample: https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/4-WebApp-your-API/4-3-AnyOrg but you would have the same clientID (and app) for your web app and web API.
Please also look at https://github.com/AzureAD/microsoft-identity-web/wiki/Mixing-web-app-and-web-api-in-the-same-ASP.NET-core-app

Should I use Identity Server 4 for a single SPA client?

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?

IdentityServer4 External Authentication without cookies

I'm having trouble understanding how ASP.NET Core authentication works.
I want to implement JWT access token authentication with refresh tokens. To my knowledge, this is the industry standard for authenticating a client (Mobile app, SPA Web application). For security purposes, I'd prefer to not implement my own authorization logic including JWT generation and refresh token handling. Since ASP.Net does not natively support this, Naturally my choice would be to use IdentityServer4, a large open source library for handling this kind of stuff.
However IdentityServer4 is heavily based on OAuth, and I'm not sure how that works with SPA applications and mobile apps (clients I trust). It requires the client to redirect to some arbitrary webpage to enter their credentials and then redirect back to the app. Gross. I've never seen a major app like Snapchat, Instagram, etc. have this kind of authentication flow where you are directed to some webpage/browser during the login flow. Luckily IdentityServer4 has a little feature to handle username/password authentication for my trusted clients (http://docs.identityserver.io/en/latest/quickstarts/2_resource_owner_passwords.html)
Great, that seems to suit my needs. But... Now I want to add Facebook Authentication. IdentityServer4 allows for External Authentication, however it is still cookie based (to my knowledge). Which requires the Android/iOS/SPA app to redirect to a webpage and then redirect back to the app. Again, this isn't ideal from a user perspective. Facebook provides native mobile SDKs to handle this type of authentication which returns an access token so there is no need to redirect to web pages using cookies.
Now lets say my iOS app uses the Facebook SDK to grab an access token for the user and sends it to the backend. The backend validates the token against the Facebook SDK, and subsequently registers a local user in it's own database.
Now when that same iOS user tries to login to the app, the app will generate a facebook access token for that user from the SDK and send it to the backend. However I'm not sure how to utilize IdentityServer4 to generate a JWT for the user since I need that users' username and password. This is where I'm stuck. I seem to be fighting against the library which makes me believe I am severely misunderstanding something.
TLDR; IdentityServer4 seems to be heavily based on cookies which doesn't really fit nicely into mobile apps/SPA webpages when you are redirected back and forth from authentication webpages. Am I using the wrong tool for the job? What are some alternative solutions?
As a note on big social apps: I think it comes down to who keeps the passwords. Facebook, Instagram, Snapchat, Google act as identity providers to third parties. They themselves require user to register and specify the password which they keep. Therefore they can use any customized approach for handling validation with those passwords. However, if any of them offerred a posibiltty to log-in with the other I.e Instagram were allowing to sign-in with Amazon credentials, then they would need to follow through a standard way like OAuth and redirect to the third party for log-in. Last time I checked Instagram, Facebook and Snapchat only offer to register and no option to sign in with 3rd parties which explains why the don't need redirects.
Now if we establish that a redirect is a necessary evil, then the means to carry over the data accross aren't that numerous. I.e. we either would need to pass data via a query string or use cookies. Am I missing any others?
Both have limitations but since cookies are persisted and browser carries them automatically with each request, they do seem like a better option for the job, especially if multiple redirects are required for an external IdP to track the state of authentication request. The same reason is mentioned here:
http://docs.identityserver.io/en/latest/topics/signin_external_providers.html
It's absolutely the right tool for the job if you want what OpenID Connect and OAuth2 give you. It sounds like you may need convincing though and it may be that your use case doesn't need the full breadth of functionality offered.
If you have multiple client applications and APIs in play then I think using OpenID Connect and IdentityServer4 the right choice at this point in time.
Regarding native apps, you used to word "gross" to describe using the user's default browser to perform the sign in process and it's understandable why you might think that at first but it's not as bad of a UX as you'd think and has plenty of advantages:
The client application is completely decoupled from how authentication is actually done be that federation, social sign in (Facebook in your case), multi-factor, retina scan etc. Your identity server deals with all that complexity and is a single point of management (and failure - so make it highly available!)
Single sign on is possible - if they're already signed into your IDP then they can go straight in (although you have full control of the flow - want them to consent or confirm the sign in request every time - you can do that)
If the user has a password manager set up in their browser then that'll work too
Both iOS and Android offer APIs for doing this stuff and the work well. If you skin your native and web UIs to look similar the flow from a user's PoV is not jarring at all.
You can still use refresh tokens (ultimately secured by the platform) so you don't actually have to do the interactive flow very often anyway.
Some additional reading below. Quite a lot of thinking has gone into this from the industry so it's definitely worth digesting the current best practice.
https://developers.googleblog.com/2016/08/modernizing-oauth-interactions-in-native-apps.html
IETF current best practice: https://www.rfc-editor.org/rfc/rfc8252
Don't make Scott hate you ;) : https://www.scottbrady91.com/OAuth/Why-the-Resource-Owner-Password-Credentials-Grant-Type-is-not-Authentication-nor-Suitable-for-Modern-Applications
For client side SPA browser apps OIDC provides the implicit grant type and uses a silent refresh and IDP session monitoring mechanism to maintain the session. Check out the oidc-client-js library which implements this approach.

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.

ASP.NET Core Web API + Angular 2 Authorization and Authentication

I have Angular 2 application which talks to the Web API and does some basic CRUD operations. I have few questions:
Is any way I can create a Login/Register page on Angular 2 using ASP.NET Identity?
How do I manipulate with a data only relates to the logged in user? (Token Based Authentication? How it works? Where to read about it?)
How can I implement login/register process on actual Angular 2 application without redirecting me to Identity Server?
I looked at IdentityServer4, OAuth2 and OpenID examples, it is a bit too complex to understand. I went thru every single step in quick start, it works but I don't understand how and what it does.
Can someone give me any resources where I can start from? Blogs, websites, books, step-by-step guides.
You're correct that at this point the most comprehensive solutions for authentication and authorization in systems that rely heavily on HTTP are based on OAuth 2.0 and OpenID Connect. This of course includes your specific scenario of a SPA calling a Web API back-end. For further read on this generic case you can check the Auth0 SPA + API Architecture Scenario or give a look at the quickstarts focused on your selected technologies:
Angular2 Quickstart
ASP.NET Core Web API Quickstart
Note: Auth0 supports OAuth 2.0/OpenID Connect so even though the docs may have additional features that are provider-specific, you may find them useful if you do indeed decide to go the OAuth 2.0/OpenID Connect route. It's one of the advantage points of relying on standards, it's easier to switch between implementation/providers.
However, you should also consider if you really need to go full OAuth 2.0/OpenID Connect as they aim to solve a lot of different use cases and as such also bring significant complexity with them. If you go that route, it's recommended that you leverage existing libraries like IdentityServer or cloud providers like Auth0, because doing your own implementation carries a lot of risk and requires significant effort.
In order to meet your requirement of providing an integrated login from within your own Angular2 front-end you could probably look into the resource owner password credentials grant specified by OAuth2.
Another alternative is doing your own custom solution, this is generally frowned upon, because it's easy to get wrong, but the theory would be:
Handle user authentication and registration (possibly using ASP .NET Identity)
Upon login exchange user credentials with some a token that you can later use to call into the API
The token could just be a random (not guessable) value used as a reference to some server-side storage that would contain information about the associated user.