Remix authentication and nested route loaders - authentication

I have a Remix app with routes like defined below, where I want a, b and c to be authenticated routes:
root/
└── a/
├── b
└── c
In route a loader I check for an authenticated user:
// in a.tsx, inside `loader` function
authenticator.isAuthenticated(
{...},
failureRedirect: '...'
)
This works fine since loading /a/b triggers a loader, which redirects upon auth failure.
But do I also need to do the check authentication in loaders for routes b and c?
Since a loader is not triggered when navigating from /a/b to /a/c, is it safe to assume in c loader that user is authenticated? And if not, what's the Remix way? Calling isAuthenticated in every segment would be very cumbersome.
Thanks

Yes. With Remix, each route loader is independent. They will be called in parallel, and sometimes your ancestor loaders won't even be called.
So generally, you should protect each loader. Typically this is done via a function like const user = await requireUser(request)
The function would validate that you have a logged-in user and throw a redirect to the login page if not.
I also add a check in my express entry to see if I have the auth token before handing the request to Remix. I have a whitelist of public routes. This way ALL routes are protected by default, and I have to specifically opt out.
Anyway, Remix is working on adding a beforeLoader export for this type of scenario. https://github.com/remix-run/react-router/discussions/9564

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.

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

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?

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.

Nuxt.js auth: Redirect after login doesn't occur for nested routes, only basic routes

I'm trying to use the #nuxtjs/auth module for OAuth2 authentication from Okta in a web app.
My app has a URL structure like: /browse/{folder} to view images from a particular folder, where {folder} can be any string of text. This is accomplished by creating a top-level view called browse.vue, a folder called browse, and a child component within that folder called _folder.vue. See more on nested routes in the Nuxt.js documentation in more detail here.
I've added the auth guard to the _folder.vue file. When I navigate to /browse, I'm redirected to /login and everything works perfectly from here with OAuth2 and Okta. When I'm returned to the app after logging in, I'm taken back to the /browse page.
However, when I navigate to a folder, like /browse/Test, I'm not redirected back to that folder after logging in. Instead, I'm returned to the / view of the app. From here, if I type the path in the address bar again, I am able to successfully view it as a logged in user. This indicates that the login was successful, but something about the redirect wasn't.
I noticed by looking at the cookies in the Firefox developer tools that an auth.redirect cookie is not created when I navigate to /browse/Test, so I think the auth module is not aware of where to redirect the user after logging in. When I navigate to /browse, the auth.redirect cookie is created, and the redirect occurs successfully.
Is there something I can do to make the auth module work for redirecting to these dynamic routes, or is this a bug with the module? Everything else about the module has worked perfectly in my app.
My auth configuration in nuxt.config.js, using #nuxtjs/auth version 4.9.1:
auth: {
fullPathRedirect:true,
redirect:{
callback:"/login",
logout:"/"
},
strategies: {
social:{
_scheme: 'oauth2',
authorization_endpoint: "https://{my-subdomain}.okta.com/oauth2/v1/authorize",
scope: ['openid', 'profile', 'email'],
access_token_endpoint: "https://{my-subdomain}.okta.com/oauth2/v1/token",
response_type: 'id_token',
token_type: 'Bearer',
client_id: process.env.CLIENT_ID,
client_secret:process.env.CLIENT_SECRET,
token_key: 'id_token'
}
}
}