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

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'
}
}
}

Related

Post login redirect logic does not work with TestCafe roles

I'm writing e2e test for a React SPA. I have login logic that works as follow:
If the user access a protected route without being logged in, the route is saved in localStorage (post_login_redirect) then the user is redirected to login page.
After a successful login, if post_login_redirect exists in localStorage, the user is redirected to the saved route, otherwise he is redirected to home (/).
In my test I call useRole in the fixture beforeEach hook. See below:
const adminUser = Role(
`http://myapp.com/login`,
async t => {
await t
.typeText('input[name="username"]', "admin#admin.com")
.typeText('input[name="password"]', "12345")
.click('button[type="submit"]');
}
);
fixture("Some fixture").page("http://myapp.com/companies/").beforeEach(async t => {
await t.useRole(adminUser);
});
test("Company list", async t => {
await t.expect(Selector("div").withText("COMPANY LIST").exists).ok();
});
What happens when I run this test:
Testcafe navigates to /companies
My app code detects the user is not logged in, create post_login_redirect and redirect to /login
Testcafe execute my Role by navigating to /login and submitting the form
My app code redirects the user to / (instead of the intended /companies/ saved in localStorage)
Testcafe navigates to /login
For what I could see, at step 3, the localStorage is being cleared which explains step 4.
Step 5 is not performed if I use preserveUrl:true on my Role. Anyhow it should navigate to /companies as it's the URL defined by my fixture.
I would expect either my localStorage from step 2 to be restored after the Role execution or either Testcafe to remember the actual URL it needs to navigate to after the Role execution.
Thanks for your help.
Your test seems to be correct, and TestCafe should work with it. The use of the Roles mechanism should not clear localStorage, so this is unexpected that your post_login_redirect value is cleared.
We would like to assist you in researching the issue. Please create a separate issue on GitHub using the following link and share your project or create a minimal example that demonstrates the issue: https://github.com/DevExpress/testcafe/issues/new?assignees=&labels=&template=bug-report.md.
If you cannot share your project on GitHub, you can send it at support#devexpress.com

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.

Deploy Vue.js Okta Authentication app on Netlify

I recently built a Vue.js application with Okta authentication. I am attempting to deploy this application on Netlify. After setting up a new project in Netlify, I imported the Vue.js application into the Netlify project from GitHub. I reconfigured the router in the application so that redirect_uri in the Okta initializer reflects the new Netlify URL:
import Auth from "#okta/okta-vue";
Vue.use(Auth, {
issuer: "https://xxx-xxxxxx.okta.com/oauth2/default",
client_id: "xxxxxxxxxxxxxxxxxxxx",
redirect_uri: "https://xxxxxxxxx-xxxx-xxxxxx.netlify.com/implicit/callback",
scope: "openid profile email"
});
After deploying the application and clicking the login button, I should be redirected to the default Okta login page. However, I am instead redirected to a page that says "page not found: Looks like you've followed a broken link or entered a URL that doesn't exist on this site."
I even made sure to whitelist that URL in my Okta dashboard. Any idea why Netlify doesn't recognize the new redirect_uri? Thanks!
Since you're deploying a SPA, you need to route all routes to your index.html and let Vue handle them.
According to this article, you need to add a _redirects file to your publish directory with the following line to take advantage of browser history pushstate:
/* /index.html 200
For more info, see Netlify's docs.
I solved the CORS issue. In the Okta Dashboard, I added the redirecting URL as an original URL under API > Trusted Origins. I selected Add Origin to specify the base URL of the website, then selected CORS. See : https://support.okta.com/help/s/article/CORS-error-when-accessing-Okta-APIs-from-front-end

How do I get react-native-inappbrowser-reborn to trigger success upon successful Facebook login

I'm trying to setup a manual flow for Facebook login, as per the docs at: https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/
I've got my test Facebook app working as expected, i.e., I can login using a private web browser window fine. The URL I'm using is:
https://facebook.com/v3.3/dialog/oauth?client_id=<app_id>&display=popup&response_type=token&redirect_uri=https://www.facebook.com/connect/login_success.html
Now within my React-Native app, I'm using react-native-inappbrowser-reborn to present a SFAuthenticationSession on iOS. As per their docs (at https://www.npmjs.com/package/react-native-inappbrowser-reborn), I'm doing the following:
const redirectUri = "https://www.facebook.com/connect/login_success.html"
const url = "https://facebook.com/v3.3/dialog/oauth?client_id="+appId+"&display=popup&response_type=token&redirect_uri=https://www.facebook.com/connect/login_success.html"
InAppBrowser.isAvailable()
.then(() => {
InAppBrowser.openAuth(url, redirectUri, {
// iOS Properties
dismissButtonStyle: 'cancel',
// Android Properties
showTitle: false,
enableUrlBarHiding: true,
enableDefaultShare: true,
})
.then((response) => {
// Only gets to this point if user explicitly cancels.
// So this does not trigger upon successful login.
})
// catch handlers follow
Using the above, my app correctly open up an in-app browser and I can login fine using a test user for my test app. Upon successful login though, I don't get redirected back to the .then completion handler. It just stays in the in-app browser view and I see the same message from Facebook that I see when logging in using a web browser. It says something like "Success. Please treat the url the same as you would a password", or something like that.
I may be missing something here, but I thought the purpose of passing redirectUri as an argument to openAuth was so that upon redirection to that URI, the completion handler would be triggered.
Question: How do I redirect back to the completion handler upon login success?
I think that you already have a solution but thought it might be useful for someone else facing this issue. If you don't have a solution so far follow my instructions:
You can't directly redirect back to your application using deep link, since Facebook will not call a link `like myapplicationname://mycustompath´. It's only possible to call links using the https-protocol (https://...).
The solution I'd suggest you to use is to redirect using your own API (Facebook -> Your API -> Deep Link Redirection). You will understand why this is required in the most of the real world applications at the end of the instructions.
Starting from your react-native app call the authorize endpoint of Facebook with a redirection to your application and set the global deeplink of your app as redirect uri.
InAppBrowser.close();
InAppBrowser.openAuth("https://graph.facebook.com/oauth/authorize?client_id=YOURCLIENTID&redirect_uri=https://YOURDOMAIN:PORT/auth/facebook", "{YOURAPPSDEEPLINKNAME}://{SOMEPATHYOUWANTTOEND}")
.then((response) => {
handleAuthorized(response, LOGINTYPE.FACEBOOK);
});
Now after login you'll be redirected to your API with the authorization code token as query parameter (e.g. https://YOURDOMAIN:PORT/auth/facebook?code=AVERYLONGCODESENTBYFACEBOOK)
Using this code token from the query parameter, you make another API Call to get the access_token for the user
{GET}: https://graph.facebook.com/v15.0/oauth/access_token?client_id=YOUR_CLIENT_ID&redirect_uri=https://YOURDOMAIN:PORT/auth/facebook&client_secret=YOUR_CLIENT_SECRET&code=AVERYLONGCODESENTBYFACEBOOK
Facebook's API will send you an answer as JSON with the access_token inside.
You can make another call using the access token of the user, to get the userId and the username
{GET}: https://graph.facebook.com/me?access_token=ACCESS_TOKEN_SENT_BY_FACEBOOK_IN_PREVIOUS_GET_REQUEST.
If you need the e-mail address for the user you have to make another call. Make sure you'd set the permission to read the e-mail address for your app on the developer portal of facebook.
The following request will return you the id, name and the email of the user
{GET}: https://graph.facebook.com/USERIDFROMPREVIOUSREQUEST?fields=id,name,email&access_token=ACCESSTOKEN
I think you want to save all these information to a database and create a session in order to keep the user logged in and therefore all the requests described will be useful for you in a real application.
After doing all the backend stuff, you're ready for the redirection using deep link. To do that, set a meta-tag to redirect the inappbrowser to your application:
<meta http-equiv="refresh" content="0; URL={YOURAPPSDEEPLINKNAME}://{SOMEPATHYOUWANTTOEND}" />

Authentication with vuejs and laravel

Where have I to authenticate in a SPA application using laravel and vuejs? I'm developing a normal web application with laravel and blade. Nothing out of ordinary, but, now, I'm trying to make a spa application using laravel and vuejs - backend separeted from frontend. Where would I have to authenticate in this example? In php routes or vuejs routes or both? My laravel app, only laravel, it works as expected, user permissions, user session, a normal application but in vuejs, how I can do the same verifications as well?
Without knowing you exact Laravel authentication setup I would just say you authenticate through ajax at the same route as you do in Laravel. In a fairly standard setup using axios I do it like this.
ajaxLogin(){
axios.post('/login',{
email: this.loginEmail,
password: this.loginPassword
}).then(function (res) {
this.getCrsfToken(); //refresh crsf token
}.bind(this));
}
Notice the getCrsfToken function here. This may be necessary if your SPA (page) is not being refreshed when logging out and back in. Like in the case of the session expiring while the browser window is open. You would use something like the following to refresh the crsf token if you are including it the standard Laravel way in the header.
In your Routes or Controller
Route::get('/getToken', function(){
return csrf_token();
})->middleware('auth');
In your Vue component
getCrsfToken(){
axios.get('/getToken')
.then(function(res){
// Refresh crsf token from session after login
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = res.data;
});
},