Seperate Front and Back-End - Persistent Authentication with Vue/Webpack/Hapi - authentication

I apologize in advance for the wall of text.
I'm working on a project for school. We are trying to create a messenger application with a separate front/back-end.
For the back-end we decided to use Hapi (NodeJS), which is now a working API that authenticates based on JWT.
Let's assume the back-end is running on http://localhost:3000.
To interact with the API and create an actual user-friendly messenger, we decided to go with VueJS, using Vuetify as a design framework.
We created a webpack template with vue create (Vue CLI3) and started designing a register/login page, which is served on http://localhost:8080.
I have now arrived at the point where I have to think about a way to show different content based on authentication. I can request a JWT from the API by logging in, but I don't want to store it in local storage, as that is insecure. The same goes for cookies, if they are not HttpOnly.
I feel like a messenger app wouldn't require a user to login every time they restart their browser, so I need some kind of persistence, which leaves only one option (please correct me if I'm wrong): HttpOnly cookies containing our session data, a JWT in this case.
Seeing as I can't set HttpOnly cookies with Vue (as it's JS), how would I go about creating persistent authentication?
We want a user to be redirected to a login page if they aren't logged in. If they are, they can access and see extra functions (Vue components). If they refresh, or restart their browser, they should still be logged in and able to access the functions the API offers (like sending messages to others, reading their own messages). This, while not being vulnerable to XSS.
I have unleashed my Google-fu for 2 days straight now and can't find a good answer. People use VueX which isn't actually persistent and only works persistently with local storage, which again, is insecure for storing a JWT.
Is this at all possible with a separate front/back-end? If I send back a cookie with Hapi, that might work and get stored in the browser, but that'll be HttpOnly so how do I read it with the front-end to determine if I am authenticated?
Please be as verbose as possible, as I seem to miss a lot of design principles and context that are apparently very obvious to everyone else on the internet. I honestly believe that if there is a very good answer to this, that it'll help other people starting out tremendously.
TL;DR: How to create persistent authentication with a Vue front-end and Hapi back-end, without sacrificing security?

as I know, HTTPOnly cookies can be set only on https protocol
source : https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#Secure_and_HttpOnly_cookies
and I think it is safe to store jwt token in localstorage as long as you use https
another related thread about jwt storing in reactjs : https://stackoverflow.com/a/44209185/10661914

Related

CSRF, CORS and my approach to authentication

I've seen many questions about CSRF attacks and GET requests, and I'm trying to work out what I need for my app's authentication system.
My stack is an SPA React app hosted at app.site.com, and an API at api.site.com.
My plan is to do the following.
On load, the React app will call a GET route on the server to get the current user.
This route will check the cookies, look for an httpOnly cookie with a valid token, and if so, send back a loggedin token which will be stored in application memory.
Each subsequent request will then be checked for both tokens in order to succeed.
A potential flaw in this that I can see is as follows:
Could an attacker send a victim to www.other-domain.com, which will trigger a script that calls my /user endpoint? That would send the httpOnly cookie, so the bad site/script will now get back my application memory token, and could then theoretically send other requests. I know I can protect against CORS with this, but is that enough?
I've read that CSRF is a 'write-only' attack, but in this instance I can see that it could be a problem on a GET request.
My questions, then, are:
Is the setup above workable from a security standpoint?
Would using a samesite cookie for the httponly cookie negate the need for the application memory token?
Are there any points in this process that I'm missing?
I've done a lot of research, but would love to hear the thoughts of more experienced engineers. Thank you in advance for any help you can provide.
I've read that CSRF is a 'write-only' attack
In general you're right. CSRF can be used to execute a create or delete action (or any other side effect) on the server - which depending on your server implementation can also happen with a GET request. In some rare cases CSRF can also be used for DoS (Denial-of-Service), for example when you have a very expensive server-side computation in your API, that can be triggered too easy and often via CSRF.
Are there any points in this process that I'm missing?
You would need CORS for your scenario to work (SPA on app.site.com and API on api.site.com). I'd try to avoid using CORS if possible, because 1. it can introduce security problems if configured poorly, 2. it can have a negative impact on performance when the browser runs preflight requests, which effectively will double the roundtrip time, and 3. you introduce tight coupling between your SPA and your API.
And that's where BFF (backend for frontend) comes in handy: You simply use app.site.com/api for your API calls from your SPA, and your app.site.com server will act as a proxy and forward these requests to api.site.com.
Now you don't need CORS at all, and you decoupled your SPA and API, because now you can intercept your API calls at the BFF level and transform the requests made to the API and also transform the responses, aggregate data, combine multiple API requests, etc.

How do I do auth for SPA + API?

Okay, so long question ahead.
I'm working on an Angular + .NET Core app and I'm a little confused as to what is the best way to do authN & authZ for my app.
For a while before, what I would do is have a page on my frontend which requests the E-mail and Password and send it via POST to my backend, where I would generate a JWT Token. Then, I would store this token in the localStorage and use it for requests.
But, after reading some articles, I noticed that people tend to do it in another way. From what I understand, it goes something like:
Create a traditional auth app
When the user wants to log in on the SPA, redirect them to the auth app, where they log in
After logging in, redirect back to SPA and store the token in memory
Use the stored token to authenticate & authorize requests
Profit
I've also been reading and getting into using Auth0, which seems to be using the latter approach. My problem with Auth0 currently is that I need to have an Users table in my local database for things like getting additional user data (I know about the metadata that can be added in Auth0, but isn't it slower to have to get data from Auth0 everytime I need to use user metadata?) & relationships, but the Hooks don't work when my app is on localhost.
Anyways,
TL;DR
Is there a standard way of doing this that is currently recommended everyone does
Do I understand correctly how the latter approach actually works
Is the way I was doing auth that insecure? From what I understand, the insecurity comes from storing the JWT Token in localStorage, but the token actually needs a secret key to be generated, so does it matter if an ill-intentioned user can see their token? They can't tamper with it without the secret anyways
I would check out these two resources and I do agree with the conclusion to put all of the token handling in the backend, not in the SPA client.
alert‘OAuth 2 0’; // The impact of XSS on OAuth 2 0 in SPAs
SPAs are dead!?

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

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

Token authentication with rest backend secure enough

I would like to secure my mobile app ( hybrid app, build with ionic framework). On backend site I use the play framework. I would implement the following case. The user of the app should authenticate to rest backend by email and password, if the credentials correct the backend generates an token return ok with the generate token to client, otherwise the backend return bad request. If the user would try to login with incorrect credentials more then 10 times the user would deactivated for 1 hour.
The mobile app would load json data from backend with ajax calls, on each call in header would set the field 'X-AUTH-TOKEN' and the generate token. The backend check the token and if the token is correct the client get data from server with status ok else the client get none data and the status unauthorized. If the user logged out the token would destroyed on server and client side. The token would not change as long as the user is logged in, in worst case the token would not changed over more than many days. I could implement, that on each call the date of last call can saved and if the last call is more than x days in past the server return unauthorized and destroy the token. So the user should logged in. Is the case secure enough, or should I implement more logic?
What you are describing is very similar, if not identical to the many, many implementations of OAuth2. For more information on these types of flows, including diagrams, check out how Google describes their OAuth2 processes here: https://developers.google.com/accounts/docs/OAuth2
I'm not familiar with the play framework but you should speak with framework experts to see if there is a well-tested, battle-hardened oauth2 implementation out there for the Play Framework. If so, you want to use that. You really don't want to (and shouldn't) roll your own implementation unless you know what you're doing and are willing to pay for people to pentest it. Really, please don't do this if unsure.
On the Ionic Framework / Angular / Cordova side, you've basically got it correct, but should always consider some basic security considerations:
My guess is that you'd use local storage to store the access token. In REST we don't have sessions like in a traditional web server scenario so we use the token in lieu of the session. Of course the downside is that local storage can easily be inspected to obtain the access key if someone had either root access on the device and was able to work their way into the app sandbox and knew exactly what api key to grab from local storage, but if someone has root or physical access to the device then you've got a bigger problem, so this isn't a design flaw per-say. To a certain extent, using this method you're relying upon the OS/browser's local storage sandbox to prevent other apps from accessing the local storage in your ionic app. This is a bet I would be willing to make, but you'll need to judge that based on your security vs usability needs.
What you should really be focusing on is protecting the token from people who may be listening on the wire (think coffee shop wifi). This means setting up your auth rest servers to use exclusively HTTPS (don't fail back to HTTP). This may have downsides, but will be worth it to protect your user's data. You also correctly identified using the token header. You should never pass auth tokens in anything but the header or POST data.
Generally speaking, what you are describing should be safe for use in a consumer level app. This assumes you don't unwittingly use any malicious third party code in your app. As always, you should be especially wary of third party code and only use code that you absolutely trust. Any code run from inside your app can access local storage in the Cordova/browser local storage sandbox and could theoretically export the api token for use in other software to access your api. With that said, you asked about authentication and not authorization. Keep in mind that your users need to only have access to do certain things in the app based on user-roles or some sort of ACL. This authorization outside the scope of this answer but you need to ensure that this is done on the server side and has rate limiting or soft-deletes for shared resources to prevent a malicious user from deleting everything.
Good luck with ionic and have fun.