Nuxt Auth Module c5 doesn't refresh token automatically when token expires - authentication

Version
module: 5.0.0-1624817847.21691f1
nuxt: 2.15.8
Nuxt configuration
Universal
Nuxt configuration
// Auth: https://auth.nuxtjs.org/ (v5)
auth: {
redirect: {
login: '/account/login/',
logout: '/account/login/',
callback: '/account/login/',
home: '/account/beams/'
},
strategies: {
local: {
scheme: 'refresh',
token: {
property: 'access_token',
maxAge: 120, // seconds, 2 minutes
global: true
},
refreshToken: {
property: 'refresh_token',
data: 'refresh_token',
maxAge: 1209600 // seconds, 2 weeks
},
user: {
property: 'user',
autoFetch: true
},
endpoints: {
login: { url: '/api/account/login', method: 'post', propertyName: 'token' },
refresh: { url: '/api/account/refresh', method: 'post', },
logout: { url: '/api/account/logout', method: 'post' },
user: { url: '/api/account', method: 'get' }
},
autoLogout: false
}
}
},
Additional information
Checklist
[x] I have tested with the latest Nuxt version and the issue still occurs
[x] I have tested with the latest module version and the issue still occurs
[x] I have searched the issue tracker and this issue hasn't been reported yet
Steps to reproduce
What is expected?
When a user's token expires and refresh scheme is implemented, a user shouldn't be logged out and redirected back to the login screen, the refresh token should be used to obtain a new token and the transition should be seamless allowing any authenticated route to continue to work.
What is actually happening?
In my Nuxt project with the Auth module I've implemented the refresh scheme, however, when my token expires I don't see any request in my network being made to the refresh route after my token expires and I navigate to a protected page via the auth middleware.
I expect I'm missing some simple configuration?
My current token has an expiry of 1 minute for testing, and my refresh token has an expiry of 14 days for testing.
However, when adding:
scheme: 'refresh'
refresh: { url: '/api/account/refresh', method: 'post', }
the functionality appears to not be fetching my user and automatically logging me in.
My /api/account/refresh endpoint in my API returns the following:
{
refresh_token: 'my refresh token',
token_type: 'bearer',
expired_in: 5000
}
My /api/account/login endpoint in my API returns the following:
{
access_token: 'my token',
token_type: 'bearer',
expired_in: 1000
}
What am I missing?

You need to return refresh token from /api/account/login. And then set in conf property name of it.

I have same issue with very similar comfiguration. This is my result from API (I added refresh token to the result):
{
"access_token": "XXX",
"refresh_token": "XXX",
"expired_in": 3600,
"token_type": "bearer"
}
If I inspect cookies, I can see acces token, but refresh token does not set:
I try to manually set refresh token after login, but with same result:
const result = await this.$auth.loginWith('local', {
data: this.login,
})
this.$auth.setUserToken(result.data.accessToken, result.data.refreshToken)

Related

Can you authenticate a Nuxt.js App through a Keycloak client that has a confidental access type?

I am authenticating my Nuxt App with Keycloak through the Auth Module for Nuxt.js. (https://auth.nuxtjs.org/)
When the access type of my Keycloak client is set to public, everything is working as intended. Now I am trying to set the access type of my Keycloak client to confidential. But it is not working. After successfully login in my Nuxt App is caught in a Redirect Loop.
Are any of my configurations wrong or did I forget something?
Here are my OAuth2 scheme configurations:
auth: {
cookie: {
options: {
HttpOnly: false,
Secure: true
}
},
strategies: {
local: false,
keycloak: {
scheme: 'oauth2',
endpoints: {
authorization: `${process.env.KEYCLOAK_HOST}/auth/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/auth`,
userInfo: `${process.env.KEYCLOAK_HOST}/auth/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/userinfo`,
token: `${process.env.KEYCLOAK_HOST}/auth/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/token`,
logout: `${process.env.KEYCLOAK_HOST}/auth/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/logout?redirect_uri=` +
encodeURIComponent(process.env.FRONTEND_SCHEME + '://' + process.env.FRONTEND_HOST)
},
token: {
property: 'access_token',
type: 'Bearer',
name: 'Authorization',
maxAge: 1800
},
refreshToken: {
property: 'refresh_token',
maxAge: 60 * 60 * 24 * 30
},
responseType: 'code',
grantType: 'authorization_code',
clientId: `${process.env.KEYCLOAK_CLIENT_ID}`,
clientSecret: `${process.env.KEYCLOAK_CLIENT_SECRET}`,
scope: ['openid', 'profile', 'email'],
codeChallengeMethod: 'S256',
vuex: {
namespace: 'auth'
},
redirect: {
login: '/login',
logout: '/',
callback: '/',
home: '/'
}
}
}
},
Here are my Keycloak client settings
I tried adding the clientSecret to my OAuth2 configurations but it didn't help either. Even if it helped I am asking myself if it is the correct way to have confidential data in my Nuxt App.
It's unclear which nuxt version you are using and keycloak version.
Can this demo help you?
https://github.com/Kingside88/nuxt3-primevue-starter-auth

Laravel Sanctum + Nuxt Auth problem with stay user logged in after CSRF expired

I'm using Laravel Sanctum + Nuxt Auth
I have some problem with understanding logic in this case.
Laravel sanctum using token with lifetime and Nuxt take this token for lifetime.
But after CSRF tocken expired and User reload page User logout and should login again. Then Laravel create new tocken. So need help, how to make Nuxt regenerate CSRF, I'm using schema laravel/sanctum from package, so i had hopes about it should be from the pack.
My config of NuxtAuth is:
auth: {
redirect: {
login: '/login',
logout: '/',
callback: '/login',
home: '/'
},
strategies: {
default: {
provider: 'laravel/sanctum',
url: '/auth',
token: {
name: "Authorization",
property: 'web_token',
global: true,
required: true,
type: 'Bearer'
}
}
}
},

How to keep users logged in after browser close with nuxt auth?

I have the following inside my nuxt.config.js file:
auth: {
strategies: {
local: {
scheme: 'local',
token: {
property: 'meta.token',
global: true,
},
user: {
property: 'data',
},
endpoints: {
login: { url: '/auth/login', method: 'post' },
logout: { url: '/auth/logout', method: 'post' },
user: { url: '/auth/user', method: 'get' }
}
},
}
},
After a short (but still unknown amount of time for me), user is logged out. Also, after closing and opening the browser, user is always logged out. How could I persist the logged in state even after closing the browser? Also, why could be the reason for users be logged out after a short amount of time?
Inspecting cookies I have in my bearer token:
Expires / Max-Age:"Session"
And I have in my local storage:
auth._token_expiration.local:"1656703495434"
Using this.$auth.$storage.setUniversal('user', response.data, true) was enough to solve OP's issue.
As shown here: https://auth.nuxtjs.org/api/storage/#universal-storage

CSRF token and Nuxt-auth

I'm now trying to code a login functionality using nuxt-auth.
I've got a FastAPI server that is set to work with HTTPOnly cookies, thus it needs a csrf token for throwing a user to my client. I can't handle the token because it's HTTPOnly so no LocalStorage
Login works fine but I can't manage to get the stored user. I made that after request to my /login endpoint, Nuxt also requests a user on /me endpoint. But I'm getting the 401 response and
Missing cookie access_token_cookie
error on /me. I don't know how to handle it.
my login request method
async userLogin() {
await this.$auth.loginWith('cookie', {
data: `grant_type=&username=${this.emailInput}&password=${this.passwordInput}&scope=&client_id=&client_secret=&`,
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
})
await this.$router.push('/account')
}
I read that nuxt-auth is bad at cookie patterns but the post was from 2018 and we have a 'cookie' strategy now. So is there a workaround of it's better to handle authentication manually?
my auth key in nuxt.config.js
auth: {
strategies: {
cookie: {
endpoints: {
login: {
url: "/api/v1/login/login",
method: "post",
withCredentials: true
},
logout: { url: "/api/v1/login/logout", method: "post" },
user: {
url: "/api/v1/users/me",
method: "get"
}
},
tokenType: "bearer"
}
}
}
I have a working http-only cookie based setup on Nuxt + Django.
My Nuxt application reverse proxies API requests to backend. So, it can read cookies on server side.
So, I create auth-ssr.ts middleware to check is user loggedIn
import { Context, Middleware } from '#nuxt/types'
import { parse as parseCookie } from 'cookie' // this is lib https://github.com/jshttp/cookie
/**
* This middleware is needed when running with SSR
* it checks if the token in cookie is set and injects it into the nuxtjs/auth module
* otherwise it will redirect to login
* #param context
*/
const authMiddleware: Middleware = async (context: Context) => {
if (process.server && context.req.headers.cookie != null) {
const cookies = parseCookie(context.req.headers.cookie)
const token = cookies['session'] || '' // here your cookie name
if (token) {
context.$auth.$state.loggedIn = true
}
}
}
export default authMiddleware
And here my nuxt.config.js
auth: {
strategies: {
cookie: {
user: {
property: 'user',
},
endpoints: {
login: {
url: '/api/v2/auth/login/',
method: 'post',
},
user: {
url: '/api/v2/auth/user/',
method: 'get',
},
logout: {
url: '/api/v2/auth/logout/',
method: 'post',
},
},
},
},
redirect: {
login: '/login',
},
plugins: ['#plugins/axios.ts'],
},
router: {
middleware: ['auth-ssr', 'auth'],
},
// Axios module configuration: https://go.nuxtjs.dev/config-axios
axios: {
proxy: true,
},
proxy: {
'/api': {
target: 'https://backend.com/',
},
},
...

#nuxtjs/auth Why refresh page always redirect to login

I can't refresh page or open new tab of secure page after refresh or new tab will redirect me to login
again
Version
Nuxt.js v2.9.1
#nuxtjs/module: 4.8.4
secure page
middleware: ['auth'],
middleware of auth-module
login page
middleware: ['guest'],
middleware/guest.js
export default async function({ store, redirect }) {
// console.log(store.state.auth)
if (store.state.auth.loggedIn) {
return redirect('/')
}
}
console.log(store.state.auth) = { user: null, loggedIn: false, strategy: 'local' }
nuxt.config.js
auth: {
strategies: {
local: {
endpoints: {
// register: { url: 'member', method: 'post', propertyName: 'data.accessToken' },
login: { url: 'api/authen-admin', method: 'post', propertyName: 'custom' },
user: { url: 'api/admin', method: 'get', propertyName: 'custom' },
logout: false
},
tokenRequired: 'Authorization',
tokenType: false
}
},
watchLoggedIn: true,
localStorage: {
prefix: 'auth.'
},
cookie: {
prefix: 'auth.', // Default token prefix used in building a key for token storage in the browser's localStorage.
options: {
path: '/', // Path where the cookie is visible. Default is '/'.
expires: 5 // Can be used to specify cookie lifetime in Number of days or specific Date. Default is session only.
// domain: '', // Domain (and by extension subdomain/s) where the cookie is visible. Default is domain and all subdomains.
// secure - false, // Sets whether the cookie requires a secure protocol (https). Default is false, should be set to true if possible.
}
},
redirect: {
login: '/login',
logout: '/login',
home: '/'
},
resetOnError: true
}
I try to use vuex-persist to persist local storage but doesn't work and when login not redirect to home path still stay login path
maybe you can use nuxtServerInit to check the login user. place in the store/index.js folder as root folder. every time you open the web for the first time, this code will run. example i use the cookie to check user loggedIn or not:
export const actions = {
async nuxtServerInit ({ commit }, { req }) {
let auth = null
if (req.headers.cookie) {
// cookie found
try {
// check data user login with cookie
const { data } = await this.$axios.post('/api/auths/me')
// server return the data is cookie valid loggedIn is true
auth = data // set the data auth
} catch (err) {
// No valid cookie found
auth = null
}
}
commit('SET_AUTH', auth) // set state auth
},
}
here the documentation
Extending Fauzan Edris answer.
I was using Auth Nuxt, following fixed my issue.
export const actions = {
async nuxtServerInit({
commit
}, {
req
}) {
let auth = null
if (req.headers.cookie) {
// cookie found
try {
// check data user login with cookie
const {
data
} = await this.$axios.post('/user/profile')
// server return the data is cookie valid loggedIn is true
auth = data.data // set the data auth
} catch (err) {
// No valid cookie found
auth = null
}
}
// How we can set the user for AuthNuxt
// Source: https://auth.nuxtjs.org/api/auth
this.$auth.setUser(auth)
},
}
You set propertyName of user endpoint to 'custom', do you receive the response with this property name? when page reload, auth plugin will try to fetchUser method to sure client still authenticated, if you didnt config user endpoint correctly, regardless of whether receive, user will set null, so you will redirect to login page, you can check what user property set by run this code:
let user = await this.$auth.requestWith(
'local', null, { url: 'api/admin', method: 'get', propertyName: 'custom' } );
console.log(user);
I'm using Nuxt with Laravel Sanctum and the thing that solved the problem for me was an issue with the SESSION_DOMAIN. I'm running the project on a subdomain and the SESSIOn_DOMAIN was set to ".domain.com", but it has to be set to "sub.domain.com".
I've got same and find out on server message, that looked impossible
[404] /api/admin
So I've tried to add BASE_URL to this request url into nuxt.config.js
auth: {
strategies: {
local: {
endpoints: {
user: { url: `${BASE_URL}/api/admin`, ... },
...
}
and issue gone