Server-side route guard middleware using the store (persisting the store in Nuxt SSR) - authentication

I'm trying to implement authentication in a Nuxt app using the Vuex store, and I hit a snag. Here's how I do it:
A middleware acting as route guard reads the value of an isAuthenticated in context.store to decide whether or not to redirect to login page. Upon completing login, the login page component mutates the store turning isAuthenticated to true before redirecting the user to their intended page.
Problem is, by the time user has completed login and is being redirected, the middleware still reads isAuthenticated as false. I'm guessing since the middleware is an SSR one its store isn't synced with the client's yet.
Looks like I need to do any (combination) of the following:
Sync the client's and server's store somehow.
Persist Vuex on SSR using a plugin or by writing my own persistence plugin.
Ditch Vuex as authentication mechanism entirely and come up with something else.
How do I work around this?

Related

Is there a way to use SSR mode in NuxtJs without any server-side requests?

Problem:
SSR has some benefits over CSR, which I'd like to have; for example, page meta-tags are delivered to client in the raw response and not in the rendered response. However, for some reasons it'd be very good for us to do all the requests on client side. That is, I like the fetch hooks to be executed on client.
I know I might be going the wrong way, but is there a way to have a client-side-only-requests SSR mode?
What I've tried:
I managed to defer fetch hooks to client using the global mixin that has a fetchOnServer: false parameter which gets injected in all pages and components. But I had another issue:
We are using #nuxtjs/auth-next (v5) for authentication and it fetches the user API on server in SSR mode unless you set user: false in nuxt.config.js file. So after setting user: false, I manually fetched the user API on all my layouts' created hook. Now the problem is that whenever I click on a link that is a nuxt-link, this.$auth.user is reset to an empty object.

How to use nuxt auth module with AWS Cognito ui

I am want to build an app which has a static frontend ( target: 'static' in nuxt.config.js ), and a backend using ktor. The app will need to authenticate users but I do not want to manage passwords and things myself, so I would like to integrate with AWS Cognito. Based on my understanding, I think this is the workflow I want:
User is browsing the site anonymously (no login)
They do some action which requires login or explicitly click on login button.
User gets redirected to AWS Cognito ui for login. They may register for new account, login with their existing, or login using another provider (after configuring cognito for it).
Cognito ui redirects user back to the app ui but with JWT tokens in query params (I think this is just how cognito does it)
The JWT token (s?) get stored in vuex store / nuxt auth
The token is used when making requests to the backend. As well as showing some additional components / actions if the user is authenticated and their basic info like username (part of jwt?)
I think I have cognito and the ktor backend setup correctly but I don't know how to get started for the frontend.
The nuxt auth module guide says to set up middleware, but afaik middleware is only for server side rendered apps.
I need to activate the vuex store but I don't know what to put there. Are there some specific things the auth module expects or do I just create an empty file in the directory?
How do I tell it when to redirect or read the token from query param?
How to parse the JWT token (if it doesn't automatically) and get some payload info like username from it?
Does the axios module get configured automatically to make use of this?
I found this old github issue 195 in the auth module repo, but I believe that's for when the "login form"/ui is part of the nuxt app and client is making use of the cognito api without 'redirect'.
Unfortunately everything in this stack is new for me so any help is appreciated. If there is already a project doing something similar, I look at the code and try to figure it out but right now I'm lost.
update 2020-12-31, mainly so that I can put a bounty on this soon: The live demo at https://auth0.nuxtjs.org/ seems to be doing what i'm looking for but then the github page read me shows something else https://github.com/nuxt/example-auth0. Also i don't see middleware / plugins used anywhere. it's all mostly configured through nuxt config, so it only works for the auth0 custom provider?
I was having the same issue as you:
How do I tell it when to redirect or read the token from query param?
I solved this by configuring auth.redirect.callback to match the endpoint that cognito will callback with the token. I believe this will tell the middleware when to look for a new token in the query param.
nuxt.config.js:
auth: {
redirect: {
callback: '/signin',
...
},
strategies: {
awsCognito: {
redirectUri: "http://localhost:8080/signin",
...
}
}
}
And to answer your other questions:
The nuxt auth module guide says to set up middleware, but afaik middleware is only for server side rendered apps.
I tried this setup with ssr: false and it still works fine.
I need to activate the vuex store but I don't know what to put there. Are there some specific things the auth module expects or do I just create an empty file in the directory?
An empty index.js file is fine.
How do I tell it when to redirect or read the token from query param?
See first answer above.
How to parse the JWT token (if it doesn't automatically) and get some payload info like username from it?
From my initial testing I found that the middleware will automatically call the userInfo endpoint when user data is requested e.g. this.$auth.user.email
strategies: {
awsCognito: {
scheme: "oauth2",
endpoints: {
userInfo: "https://x.amazoncognito.com/oauth2/userInfo",
ref: https://docs.aws.amazon.com/cognito/latest/developerguide/userinfo-endpoint.html
Does the axios module get configured automatically to make use of this?
Yes.

Does Nuxt Auth Module use serverMiddleware or client one?

I want to understand whether nuxt-auth uses serverMiddleware and if not how can i implement one. I want to make my admin panel really secured, I have my backend secured however even if someone manages to overcome auth middleware on the frontend, which won't be that difficult(if auth Module uses client-side middlewares), I don't want nuxt to provide him/her with the layout and all pages even though I know that he/she is not going to be able to do anything because my routes on the backed require token verification and account data. If you can, please provide some info on the subject. Thanks!!!
So in short you cannot use the middleware provided by the #nuxtjs/auth plugin as a serverMiddleware, you can only use it as a normal middleware.
But that doesn't mean that it's insecure, normal middlewares actually executes both on server and client side before the page is rendered, so if you want to execute a middleware that will throw a 404 if the user isn't logged in you can do this in a normal middleware too, the serverMiddleware's capabilities are actually limited, you can't access nor the store or any client side information, because you only get (req,res, next) as parameters, and since Authentication is stored in store and cookies you can't make it work in Node.js only. This is a good example of what you can use serverMiddleware for: https://jackwhiting.co.uk/posts/handling-redirects-in-nuxtjs-through-middlware/
If you console.log something in normal middleware you should be able to see it both in your developer console and bash where npm run dev is running, this would mean that first the server executes it and then the client side too.

JWT authorization in nuxt.js

I have a problem with authorization via JWT using nuxt. I want to restrict access to specific routes for users that don't have JWT token. The most proper place to check authorization in nuxt is middleware, but I can not access localStorage inside of it. I tried to set mode: "spa" in nuxt.config.js and to check if (process.browser) condition in middleware to get access to localStorage in middleware, but this condition is false for every request. So, are there any options to check JWT token existance in middleware? Should I store JWT token in localStorage? If not, where should I store it?
First you need to use process.client instead of process.browser to check if its a client or not. See docs here
isClient Boolean Client & Server Boolean to let you know if you're
actually renderer from the client-side (deprecated. use
process.client).
Second if u set mode: spa it always will be true, so this check only makes sense in universal mode.
Third you can store token both in localstorage and cookie, thats how nuxt-auth module is done. Take a loot at it, probably u will be able to use it instead of writing your own implementation, or at least you will have some ideas how its implemented

Handle authentication in a Service Worker for a React App

I have a React app rendering client-side, in which I handle authentication the following way:
Upon loading, the app fires an AJAX request to the backend, basically asking whether the user's session is valid ;
It updates the app's state with the server's response ;
It renders the "/" route accordingly (the homepage if the session is invalid, a dashboard if it is valid).
(Maybe there are better solutions for handling this in front-end applications, I'm all ears if you have ideas)
This works pretty well, but introducing Service Workers into the mix and trying to turn the app into an offline-first progressive web app seems... complicated.
On the one hand, if I don't cache the "Am I logged in ?" request and the app is offline, the app will always render the homepage.
On the other hand, if I do cache the AJAX request, the users will eventually be shown an empty dashboard because their sessions will have expired and the server will be throwing 403s.
Is there a way to handle this effectively?
I solved my problem by taking a different approach: I now persist the state in localStorage.
This way, when the user arrives on the app, he is presented with stale data from his last visit. Meanwhile, a "Am I logged in?" request is fired in the background.
If it is succesful and returns true, the other AJAX requests get fired and fill the app with fresh data ;
If it is successful and returns false, the state is updated accordingly and the user redirected to the homepage ;
If the request is unsuccessful (i.e. the app is offline) the app keeps showing stale data from last session in the dashboard. We don't know if the user's session is still valid, but we can't retreive any data so it does not matter.
One way of doing it is adding a /verifyToken (assuming you are using some kind of token to validate the session) in your back-end api to check if the token is valid.
So you cache your session token. If the app is offline it shows the dashboard.
If the app is online, you fire a request to /verifyToken to check is the session is still valid. If it is then you continue to dashboard. If it isn't you redirect them back to homepage (or the sign in page).
Edit:
When your app is online, you can technically fire a request to any authorized route and check if the response was 403 (in case you can't modify the backend). If it is then you can send them back to sign in page.