How to prevent to lost session after refresh in nuxt? - vue.js

I am currently working on a nuxtJS app in which the session seems to be lost after any refresh (although only in dev, not while deployed). I've tried to look up in the auth module of nuxt, and have tried many answers on google, but nothing seems to work and I'm a bit lost.
nuxt.config.js
auth: {
strategies: {
local: {
scheme: 'refresh',
token: {
property: 'token',
maxAge: 3600,
global: true,
},
refreshToken: {
property: 'refresh_token',
data: 'refresh_token',
maxAge: 60 * 60 * 24 * 30,
},
user: {
property: 'user',
},
endpoints: {
login: { url: '/authentication_token', method: 'post' },
refresh: { url: '/refresh/token', method: 'post' },
logout: false,
user: { url: '/api/user', method: 'get' },
},
autoLogout: true,
},
},
},
LoginMenu.js
methods: {
async onSubmit() {
try {
const response = await this.$auth.loginWith('local', {
data: this.login,
});
if (response.status === 200) {
await this.$auth.setUser({
email: this.login.email,
password: this.login.password,
});
await this.$router.push('/');
}
else {
this.loginFail();
}
}
catch (e) {
this.loginFail();
}
},
loginFail() {
this.showError = true;
},
},
nuxt auth.js
import Middleware from './middleware'
import { Auth, authMiddleware, ExpiredAuthSessionError } from '~auth/runtime'
// Active schemes
import { RefreshScheme } from '~auth/runtime'
Middleware.auth = authMiddleware
export default function (ctx, inject) {
// Options
const options = {
"resetOnError": false,
"ignoreExceptions": false,
"scopeKey": "scope",
"rewriteRedirects": true,
"fullPathRedirect": false,
"watchLoggedIn": true,
"redirect": {
"login": "/login",
"logout": "/",
"home": "/",
"callback": "/login"
},
"vuex": {
"namespace": "auth"
},
"cookie": {
"prefix": "auth.",
"options": {
"path": "/"
}
},
"localStorage": {
"prefix": "auth."
},
"defaultStrategy": "local"
}
// Create a new Auth instance
const $auth = new Auth(ctx, options)
// Register strategies
// local
$auth.registerStrategy('local', new RefreshScheme($auth, {
"token": {
"property": "token",
"maxAge": 3600,
"global": true
},
"refreshToken": {
"property": "refresh_token",
"data": "refresh_token",
"maxAge": 2592000
},
"user": {
"property": "user"
},
"endpoints": {
"login": {
"url": "/authentication_token",
"method": "post"
},
"refresh": {
"url": "/refresh/token",
"method": "post"
},
"logout": false,
"user": {
"url": "/api/user",
"method": "get"
}
},
"autoLogout": true,
"name": "local"
}))
// Inject it to nuxt context as $auth
inject('auth', $auth)
ctx.$auth = $auth
// Initialize auth
return $auth.init().catch(error => {
if (process.client) {
// Don't console log expired auth session errors. This error is common, and expected to happen.
// The error happens whenever the user does an ssr request (reload/initial navigation) with an expired refresh
// token. We don't want to log this as an error.
if (error instanceof ExpiredAuthSessionError) {
return
}
console.error('[ERROR] [AUTH]', error)
}
})
}

Related

VueJS and Axios handle errors properly

I am trying to raise an error during the login ... but weird thing is -> it does not work as I would expect it to ...
I am having this simple auth.service.js
class AuthService {
async login(params) {
try {
const user = (await axios.post('/authentication', { ...params })).data;
return true;
} catch (err) {
console.log(err);
throw new Error(err);
}
}
}
export default new AuthService();
The "err" has the full axios error object (as shown below)
{
"message": "Request failed with status code 401",
"name": "AxiosError",
"stack": "AxiosError: Request failed with status code 401\n at settle (http://localhost:3000/node_modules/.vite/deps/axios.js?v=430fef65:1124:12)\n at XMLHttpRequest.onloadend (http://localhost:3000/node_modules/.vite/deps/axios.js?v=430fef65:1335:7)",
"config": {
"transitional": {
"silentJSONParsing": true,
"forcedJSONParsing": true,
"clarifyTimeoutError": false
},
"adapter": [
"xhr",
"http"
],
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"maxBodyLength": -1,
"env": {},
"headers": {
"Accept": "application/json, text/plain, */*",
"Content-Type": "application/json"
},
"baseURL": "http://localhost:3030",
"method": "post",
"url": "/authentication",
"data": "{\"username\":\"admin\",\"password\":\"admin\",\"strategy\":\"local\"}"
},
"code": "ERR_BAD_REQUEST",
"status": 401
}
what is weird is, that when I use that in my login method .. I am getting just the name and message values ... nothing else :(
methods: {
async login() {
const payload = { username: this.username, password: this.password, strategy: 'local' };
AuthService.login(payload)
.then(() => {
this.$router.push({ name: 'home' });
this.loading = false;
})
.catch(error => {
console.log(error); // THIS DOES NOT SHOW THE ENTIRE OBJECT WITH ALL KEYS
this.loading = false;
});
},
any idea why?

Can I use Supertokens with linkedin login oauth 2.0 as Third party provider ? How to do so?

I was researching about identity providers and I found supertokens (https://supertokens.com/docs/guides), it seems a nice solution but I would like to know if it also accepts LinkedIn as a third party provider because I couldn't see any info about this in docs or in any other related post. Also if you have any example code would be awesome
Find documentation about integration between supertokens and LinkedIn auth, couldn't find any.
The documentation for implementing custom providers is available here - https://supertokens.com/docs/thirdparty/common-customizations/sign-in-and-up/custom-providers. Based on that, here is a sample implementation for linkedin that you could use:
Frontend:
export const SuperTokensConfig = {
appInfo: {
appName: "SuperTokens Demo App",
apiDomain: "http://localhost:3001",
websiteDomain: "http://localhost:3000",
},
// recipeList contains all the modules that you want to
// use from SuperTokens. See the full list here: https://supertokens.com/docs/guides
recipeList: [
ThirdParty.init({
signInAndUpFeature: {
providers: [
{
id: "linkedin",
name: "Linkedin",
buttonComponent: <div style={{
cursor: "pointer",
border: "1",
paddingTop: "5px",
paddingBottom: "5px",
borderRadius: "5px",
borderStyle: "solid"
}}>Login with Linkedin</div>
}
],
},
}),
Session.init(),
],
};
Backend:
const Linkedin = (config: any): TypeProvider => {
return {
id: "linkedin",
get: (redirectURI: string | undefined, authCodeFromRequest: string | undefined, userContext: any) => {
const accessTokenParams: any = {
client_id: config.clientId,
client_secret: config.clientSecret,
grant_type: "authorization_code",
}
if (redirectURI !== undefined) accessTokenParams["redirect_uri"] = redirectURI;
if (authCodeFromRequest !== undefined) accessTokenParams["code"] = authCodeFromRequest;
const authRedirectParams: any = {
client_id: config.clientId,
scope: "r_liteprofile r_emailaddress",
response_type: "code",
}
if (redirectURI !== undefined) authRedirectParams["redirect_uri"] = redirectURI;
return {
accessTokenAPI: {
url: "https://www.linkedin.com/oauth/v2/accessToken",
params: accessTokenParams,
},
authorisationRedirect: {
url: "https://www.linkedin.com/oauth/v2/authorization",
params: authRedirectParams,
},
getClientId: () => config.clientId,
getProfileInfo: async (authCodeResponse: any, userContext: any) => {
const headers = {
Authorization: `Bearer ${authCodeResponse.access_token}`,
}
const userInfo = (await axios.get("https://api.linkedin.com/v2/me", { headers })).data
const emailInfo = (await axios.get("https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))", { headers })).data
let email = ''
for (const element of emailInfo.elements) {
if (element['handle~'].emailAddress) {
email = element['handle~'].emailAddress
break
}
}
return {
id: userInfo.id,
email: {
id: email,
isVerified: false,
}
}
},
}
},
}
}
export const SuperTokensConfig: TypeInput = {
supertokens: {
connectionURI: "https://try.supertokens.com",
},
appInfo: {
appName: "SuperTokens Demo App",
apiDomain: "http://localhost:3001",
websiteDomain: "http://localhost:3000",
},
recipeList: [
ThirdParty.init({
signInAndUpFeature: {
providers: [
Linkedin({
clientId: "...",
clientSecret: "..."
}),
],
},
}),
Session.init(),
],
};
If you are using python or the golang SDK, a similar implementation in that language should work.

Nuxt.js Oauth sometimes crashes whole webpage

I have created Nuxt.js application, I decided to build in Nuxt/auth module, everything works fine in web browsers, but somethimes when user navigates with mobile browser my application is crushed, simply it don't respond nothing, also there is no api calls, but after one refresh everything works fine, I can not guess what's happening, I could not find anything in the resources available on the Internet.
const axios = require('axios')
export default {
// Global page headers: https://go.nuxtjs.dev/config-head
head: {
title: 'app',
htmlAttrs: {
lang: 'en'
},
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
],
script: [
// { src: "//code-eu1.jivosite.com/widget/UoBOrMfSmm", async: true },
]
},
// Global CSS: https://go.nuxtjs.dev/config-css
css: [ '~/assets/css/transition.css', '~/assets/css/errors.css' ],
pageTransition: "fade",
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
plugins: [
{ src: "~/plugins/star-rating", ssr: false },
{ src: "~/plugins/mask", ssr: false },
{ src: "~/plugins/rangeSlider", ssr: false },
{ src: "~/plugins/vueSelect", ssr: false },
{ src: "~/plugins/vuelidate", ssr: false },
],
// Auto import components: https://go.nuxtjs.dev/config-components
components: true,
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
buildModules: [
[ '#nuxtjs/google-analytics', {
id: 'xxx'
} ]
],
// Modules: https://go.nuxtjs.dev/config-modules
modules: [
// https://go.nuxtjs.dev/bootstrap
'bootstrap-vue/nuxt',
'#nuxtjs/axios',
'#nuxtjs/toast',
'#nuxtjs/auth-next',
[ 'nuxt-lazy-load', {
defaultImage: '/spin2.gif'
} ],
[ 'nuxt-facebook-pixel-module', {
/* module options */
track: 'PageView',
pixelId: '',
autoPageView: true,
disabled: false
} ],
'nuxt-moment',
'#nuxtjs/robots',
'#nuxtjs/sitemap'
],
moment: {
locales: ['ru', 'en']
},
toast: {
position: 'top-center',
},
robots: [
{
UserAgent: '*',
Disallow: ['/user', '/admin'],
},
],
axios: {
baseURL: 'https://api.test.com/', // Used as fallback if no runtime config is provided
},
sitemap:{
exclude:[
'/user',
'/admin',
'/admin/*',
'/user/*',
],
defaults: {
changefreq: 'daily',
priority: 1,
lastmod: new Date()
},
routes: async () => {
const { data } = await axios.get('https://api.test.com/api/cars/all')
return data.map((product) => `https://test.com/product/${product.id}/${product.name}`)
}
},
loading: {
color: '#F48245',
height: '4px'
},
target: 'server',
/* auth */
auth: {
plugins:[
{ src: "~/plugins/providers", ssr:false},
],
redirect: {
login: '/',
logout: '/',
home: '/',
callback: '/callback'
},
strategies: {
local: {
token: {
property: 'user.token',
},
user: {
property: false
},
endpoints: {
login: { url: 'api/login', method: 'post' },
logout: { url: 'api/logout', method: 'post' },
user: { url: 'api/user', method: 'get' }
},
},
facebook: {
endpoints: {
userInfo: 'https://graph.facebook.com/v6.0/me?fields=id,name,picture{url}',
},
redirectUri:'xxx',
clientId: '184551510189971',
scope: ['public_profile', 'email'],
},
google: {
responseType: 'token id_token',
codeChallengeMethod: '',
clientId: 'xxx',
redirectUri: 'https://test.com/callback',
scope: ['email'],
},
},
cookie: {
prefix: 'auth.',
},
},
// Build Configuration: https://go.nuxtjs.dev/config-build
build: {},
};
This is my plugins directory file, where i am handling client oauth process.
export default async function ({ app }) {
console.log('auth executed')
if (!app.$auth.loggedIn) {
return
} else {
console.log('auth executed inside loop')
const auth = app.$auth;
const authStrategy = auth.strategy.name;
if (authStrategy === 'facebook') {
let data2 = {
fb_token: auth.user.id,
first_name: auth.user.name
}
try {
const response = await app.$axios.$post("/api/oauth", data2);
await auth.setStrategy('local');
await auth.strategy.token.set("Bearer " + response.user.token);
await auth.fetchUser();
} catch (e) {
console.log(e);
}
} else if (authStrategy === 'google') {
let dataGoogle = {
google_token: auth.user.sub,
first_name: auth.user.given_name,
last_name:auth.user.family_name
}
try {
const response = await app.$axios.$post("/api/oauth", dataGoogle);
await auth.setStrategy('local');
await auth.strategy.token.set("Bearer " + response.user.token);
await auth.fetchUser();
} catch (e) {
console.log(e);
}
}
}
}
For any issues related to DOM hydration, you can check my answer here: https://stackoverflow.com/a/67978474/8816585
It does have several possible cases (dynamic content with a difference between client side and server side rendered template, some random functions, purely wrong HTML structure etc...) and also a good blog article from Alex!

How to retrieve token property in Nuxt Auth

I am developing my first NuxtJs application with the following technologies.
For Backend APIs Laravel 7.3 (Passport)
Nuxt v2.15.2
Rendering mode: Universal (SSR / SSG)
NuxtAxios v5.13.1
NuxtAuth v5
My login API response is as follows:
{
"status": true,
"code": 200,
"data": [
{
"id": 3,
"nick_name": "johndoe",
"full_name": "John Doe",
"email": "johndoe#mail.com",
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxIiwianRpIjoiNWE5MjFmMGMyMDBlZjkxYWQxY2QyNGI3NDEyYmI1OWY4ZGEyZjg2Yzc0Y2M1ZDAwOTRhOWIyZTU4MGY3MmZmODRmNGI5N2QwYjJmYjA5NjMiLCJpYXQiOjE2MTQwMzE1MDMsIm5iZiI6MTYxNDAzMTUwMywiZXhwIjoxNjQ1NTY3NTAzLCJzdWIiOiIzIiwic2NvcGVzIjpbXX0.clQslt3CdTLoVDHzQFwQyrRLjzjTOSeipCyQAl07gzmwXFKr542hR3MUCRr8CTjueWDTNbwd-iKkQztvB7Z-0N1zaptq67UEwj3iPEEtnbV2gMOSlVdAUu0q4OPJKYI9RwJKHnK-q1bTCOUOitfLrnYOq3Lb1T8B-3en5_S7xb9ln-iOtwVc3vW1OnEbEIsn3ELeTro1zQ9IKdlHhQ50CnGU45LipzKeadtVGkm9qm467XOqlVPZdulMJTCkvunETo23hQsTsn_Fxy0IYLUA0v-_C-ARB0N672fAuHF2a8MIYHv066Omm-6WsPrCNtfOkoIgyuMLl0gaua04IJfHrDbh7CJSEUqootKTsIVvFG4OjqR3yDN2PdhjJkPYWNTMeLbKV3ewSsjCS1aMOtXYvhrVFjrunn5M74pDBzn3kW9VMFIh2BbIfUDO_ziDrsn7KAVyOm-p7gdBN_gVKcl_Hx9x4EagixWRL7GGUqEZ2AbxRkpIO4HKwqMm7WxKatSt5hkmPZ6Zt-jfMTfrj7KuF6WhhjCh1TOFJSy9BTqp9_a2eKP-YL2M6JIJXFDHwovToC96JBptbumPvB2i2KDU_XoXF2WFx_I4iNJpZVFN0u12MeyMbXlnpf4X2t79_I7QklxSfZ5LgsOdsnt9dAm9QBbSvf8AdZZNOS4p59DuQls",
}
],
"error": null,
"errors": null
}
nuxt.config.js
auth: {
strategies: {
local: {
token: {
// property: 'access_token'
// property: 'data[0].access_token'
// property: 'data.data[0].access_token'
property: false
},
user: {
property: 'data',
autoFetch: true
},
endpoints: {
login: { url: '/en/signin', method: 'post' },
logout: { url: '/user/logout', method: 'get' },
user: { url: '/en/user/profile', method: 'get' },
}
}
}
},
Login.vue
export default {
data() {
return {
login: {
email: 'johndoe#mail.com',
password: 'welcome'
}
}
},
methods: {
async userLogin() {
try {
let response = await this.$auth.loginWith('local', { data: this.login })
console.log(response)
} catch (err) {
console.log(err)
}
}
}
}
When I am setting local.property: false, auth._token.local is being set as complete json object instead of "access_token" and then the second hit goes to '/en/user/profile' with Unauthenticated Request result.
I think an alternate way would be to set local.token.required:false , and then set the user token after your login attempt was successful. Something like this:
nuxt.config.js
auth: {
strategies: {
local: {
token: {
required: false
},
user: {
property: 'data',
autoFetch: true
},
endpoints: {
login: { url: '/en/signin', method: 'post' },
logout: { url: '/user/logout', method: 'get' },
user: { url: '/en/user/profile', method: 'get' },
}
}
}
},
Login.vue
methods: {
async userLogin() {
try {
let response = await this.$auth.loginWith('local', { data: this.login })
.then((response)=>{
this.$auth.setUserToken(response.data[0].access_token,'refreshToken');
});
console.log(response);
} catch (err) {
console.log(err)
}
}
}

Nuxt Auth - User Data not set

I try to do a login via nuxt-auth module. As a response I get the token and then the user data is delivered. However, this.$Auth.loggedIn is false and this.$Auth.user is undefined. I have been fighting for 3 days and can not get any further. Hope somebody can help me.
login
await this.$auth.login({
data: {
email: this.email,
password: this.password
}
}).then(() => {
this.$router.push('/dashboard')
}).catch(err => {
this.snackbar.show = true;
})
nuxt.config.js
auth: {
strategies: {
local: {
endpoints: {
login: {
url: '/auth/login',
method: 'post',
propertyName: 'access_token'
},
logout: {
url: '/auth/logout',
method: 'post'
},
user: {
url: '/auth/me',
method: 'post'
},
tokenRequired: true
}
}
}
}
response login
{
"access_token": "xxxxxxxxxxxxx.eyJpc3MiOiJodHRwczpcL1wvYXBpLmFwcHJlexxxxxxxcxXRoXC9sb2dpbiIsImlhdCI6MTUzODI5NTczMywiZXhwIjoxNTM4Mjk5MzMzLCJuYmYiOjE1MzgyOTU3MzMsImp0aSI6ImdtWWVyZTViQjk1cU5BRG8iLCJzdWIiOjIsInBydiI6IjYwODM2NzQ0MzQ4ZDQzMTk4NzE4N2ZjMWM2YzIzMjYxMDcyMWE5ZjAifQ.JhOiwIg7StzZR71aqYyI9rJpPXVclmddzPSIwqCIUN4",
"token_type": "bearer",
"expires_in": 3600
}
response user
{
"id": 2,
"name": "Dominik Dummy",
"email": "dummy#andreas-pabst.de",
"created_at": {
"date": "2018-09-28 09:11:31.000000",
"timezone_type": 3,
"timezone": "UTC"
},
"updated_at": {
"date": "2018-09-28 09:11:31.000000",
"timezone_type": 3,
"timezone": "UTC"
},
"self": "https:\/\/api.apprex.de\/api\/users\/2"
}
Ok after a long try, I finally solved it. The problem was that auth.fetchUser() requires a property user in the user response, which is not present in my user response. I set the propertyName to false in the nuxt.config.js and now it works
*nuxt.config.js
auth: {
strategies: {
local: {
endpoints: {
login: {
url: '/auth/login',
method: 'post',
propertyName: 'access_token'
},
logout: {
url: '/auth/logout',
method: 'post'
},
user: {
url: '/auth/me',
method: 'post',
propertyName: false // <--- Default "user"
}
}
}
}
}
Currently I am not sure if this is a fault in the module
Update for auth-next": "^5.0.0"
You will have to set property: false instead of propertyName.
So your nuxt.config.js might be as follows:
auth: {
strategies: {
local: {
token: {
property: 'access_token',
required: true,
type: 'Bearer'
},
user: {
property: false, // <--- Default "user"
autoFetch: true
},
endpoints: {
login: { url: 'api/login', method: 'post' },
logout: { url: 'api/auth/logout', method: 'post' },
user: { url: 'api/user', method: 'get' }
}
}
}
},
You should call the this.$auth.fetchUser() for fills user data and loggedIn in the auth store Docs