Without applying a strategy to any routes, hapi-auth-cookie is protecting all routes, including static.
server.register(require('hapi-auth-cookie'), function (err) {
if (err) {
logError(err);
}
server.auth.strategy('session', 'cookie', true, {
password: 'things really long',
clearInvalid: true,
isSecure: false,
validateFunc: function (request, session, callback) {
cache.get(session.sid, (err, cached) => {
if (err) {
return callback(err, false);
}
if (!cached) {
return callback(null, false);
}
return callback(null, true, cached.account);
});
}
});
});
Here are my routes:
{
method: 'POST',
path: '/api/1/doSomething',
config: {
validate: {
payload: someJoyObject
},
handler: function(request, reply) {
stuff
}
}
}
and
{
method: 'GET',
path: '/{param*}',
handler: {
directory: {
path: './public',
listing: false,
index: true
}
}
}
I can't load any files of my app:
{"statusCode":401,"error":"Unauthorized","message":"Missing authentication"}
Have a look at the documentation for server.auth.strategy(). You're passing true as the 3rd argument meaning hapi will apply this strategy to all routes by default.
To disable it for your static routes either:
Don't set it as a required strategy for all routes
Disable the strategy explicitly on your directory handler route:
e.g.:
{
method: 'GET',
path: '/{param*}',
config: {
auth: false
},
handler: {
directory: {
path: './public',
listing: false,
index: true
}
}
}
Related
I'm using the Nuxt/Auth library in a NuxtJs project. I'm trying to make a login request to my backend. So I don't use any of the existing schemes that the library has prepared by default.
This is what my configuration looks like in nuxt.config.js
axios: {
baseUrl: 'https://api.release.my-custom-domain.com',
credentials: true,
proxy: true
},
proxy: {
'/api/': {
target: 'https://api.release.my-custom-domain.com',
pathRewrite: {'^/api/': ''}
}
},
auth: {
strategies: {
local: {
token: {
property: 'token',
global: true,
},
user: {
property: 'user'
},
endpoint: {
login: {url: '/api/v1/auth', method: 'post', propertyName: false}
}
}
}
},
I use a proxy because of a problem with cors.
This is what my code looks like in vue.
methods: {
async loginFormSubmit () {
try {
let response = await this.$auth.loginWith('local', { data: this.login })
console.log(response);
} catch (err) {
console.log(err);
}
}
}
After I call the function, the XRH request runs, but it always adds /login to the url request.
This is what the url should look like - http://localhost:3000/api/auth
But the request looks like this - http://localhost:3000/api/auth/login
Didn't someone already solve this problem?
Thank you for your answers.
js app with Nuxt Auth and when I want to log in. User is not set and loggedIn is false
const response = await this.$auth.loginWith('local', { data: {
email: this.form.email.value,
password: this.form.password.value,
} });
this.$auth.setUser(response.data.user);
this.$auth.strategy.token.set(response.data.jwt.access_token)
this.$auth.strategy.refreshToken.set(response.data.jwt.refresh_token)
so I wrote this and after that user is set but loggedIn is still false. Here my nuxt.config.js.
auth: {
strategies: {
local: {
scheme: 'refresh',
token: {
property: 'access_token',
maxAge: 1800,
required: true,
type: 'Bearer',
},
refreshToken: {
property: 'refresh_token',
data: 'refresh_token',
maxAge: 60 * 60 * 24 * 30,
},
user: {
property: 'user',
autoFetch: true,
},
endpoints: {
login: { url: '/login', method: 'post' },
refresh: { url: '/refresh', method: 'post', propertyName: false },
logout: { url: '/logout', method: 'post' },
user: { url: '/refresh', method: 'post', propertyName: false },
},
},
},
},
Can you help me with it please?
I found solution to my answer. I wrote my own scheme
import { RefreshScheme } from '~auth/runtime'
export default class CustomScheme extends RefreshScheme {
// Override `fetchUser` method of `local` scheme
async fetchUser (endpoint) {
this.options.endpoints.user = {
...this.options.endpoints.user,
data: {
token: this.$auth.strategy.refreshToken.get()
}
}
// Token is required but not available
if (!this.check().valid) {
return
}
// User endpoint is disabled.
if (!this.options.endpoints.user) {
this.$auth.setUser({})
return
}
// Try to fetch user and then set
return this.$auth.requestWith(
this.name,
endpoint,
this.options.endpoints.user
).then((response) => {
const user = response.data.user
// Transform the user object
const customUser = {
...user,
fullName: user.name,
roles: ['user']
}
// Set the custom user
// The `customUser` object will be accessible through `this.$auth.user`
// Like `this.$auth.user.fullName` or `this.$auth.user.roles`
this.$auth.setUser(customUser)
return response
}).catch((error) => {
this.$auth.callOnError(error, { method: 'fetchUser' })
})
}
}
Apparently was the problem by getting user from propertyName. I replace code with my own response const user = response.data.user and now it seems working :)
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)
}
}
}
My auth in nuxt.config.js like this :
auth: {
redirect: {
login: '/',
home: '/home',
logout: '/'
},
strategies: {
local: {
endpoints: {
login: {
url: '/api/token',
method: 'post',
propertyName: 'response.token'
},
user: {
url: '/api/references?number=1122334433221&name=chelsea&birthDate=1995-03-18',
method: 'get',
propertyName: 'data'
},
logout: {
url: '/api/logout',
method: 'post'
}
},
tokenRequired: true,
tokenType: 'Bearer '
}
},
token: {
name: 'token'
},
cookie: {
name: 'token'
}
}
In endpoint user, I put number, name and birthDate statically. How do I make it dynamic? So the parameter is taken from the data
data () {
return {
auth: {
name: '',
number: '',
birthday: null
}
}
}
When submit login, it will call this :
methods: {
submit () {
this.$auth.loginWith('local', {
data: {
username: 'mycompany',
password: '123123123'
}
}).then((resp) => {
this.SET_IS_AUTH(true)
this.$router.push('/home')
}).catch(() => {
console.log('error')
})
}
}
Update (Using try catch)
methods: {
...mapMutations(['SET_IS_AUTH']),
async fetchUserInfo () {
const user = await this.$axios.$get(`/api/references?number=${this.auth.number}&name=${this.auth.name}&birthDate=${this.auth.birthday}`)
this.$auth.setUser(user)
},
submit () {
if (this.$refs.form.validate()) {
try {
this.$auth.loginWith('local', {
data: {
username: process.env.USERNAME,
password: process.env.PASSWORD
}
}).then((resp) => {
this.fetchUserInfo()
this.SET_IS_AUTH(true)
this.$router.push('/home')
})
} catch(err) {
commit('SET_ERROR', err)
}
}
}
}
Since you are setting the user endpoint in nuxt.config.js you won't be able to dynamically pass in the endpoint URL. However, you can achieve the outcome by passing false to the user endpoint like so:
auth: {
redirect: {
login: '/',
home: '/home',
logout: '/'
},
strategies: {
local: {
endpoints: {
login: {
url: '/api/token',
method: 'post',
propertyName: 'response.token'
},
user: false,
logout: {
url: '/api/logout',
method: 'post'
}
},
tokenRequired: true,
tokenType: 'Bearer '
}
},
token: {
name: 'token'
},
cookie: {
name: 'token'
}
}
Then you can use axios to make the request to get the user details manually passing in your dynamic values and then setting the user values for the auth module. For example perhaps when the user logs in, you can then have a method called fetchUserInfo and it would look like so:
export default {
data () {
return {
auth: {
name: '',
number: '',
birthday: null
}
}
},
methods: {
async fetchUserInfo() {
const user = await this.$axios.$get(`/api/references?number=${this.auth.number}&name=${this.auth.name}&birthDate=${this.auth.birthDate}`)
// Sets the user info using the setUser method on the auth module
this.$auth.setUser(user)
}
}
}
Here is a link to the setUser method usage. Perhaps this would help you: https://auth.nuxtjs.org/api/auth.html#setuser-user
I have been implementing an authorization step which I modeled on THIS question's answer by fragsalat.
Everything works until it reaches the line
return new Redirect('login');
upon which I get the error:
aurelia-logging-console.js:47 ERROR [app-router] Error: Expected router pipeline to return a navigation result, but got [{"url":"login","options":{"trigger":true,"replace":true},"shouldContinueProcessing":false}] instead.
at processResult (aurelia-router.js:1761)
at aurelia-router.js:1725
at <anonymous>
I am not sure why this has not just redirected?
This is the full app.ts file so you might see the context:
import { Aurelia, PLATFORM, autoinject } from "aurelia-framework";
import {
Redirect,
NavigationInstruction,
Router,
RouterConfiguration,
Next
} from "aurelia-router";
import { AuthService } from "../../auth/auth-service";
//import { Clients } from '../../public/components/login/login'
#autoinject
export class App {
public router: Router;
private TOKEN_KEY = "session";
configureRouter(config: RouterConfiguration, router: Router): void {
this.router = router;
config.title = "Aurelia";
config.addAuthorizeStep(AuthorizeStep);
config.map([
{
route: ["", "scheduler"],
name: "scheduler",
settings: {
icon: "scheduler",
auth: true,
roles: ["Employee", "Admin"]
},
moduleId: PLATFORM.moduleName("../components/scheduler/scheduler"),
nav: true,
title: "scheduler"
},
{
route: "clients",
name: "clients",
moduleId: PLATFORM.moduleName(
"../components/clients/clientList/clientList"
),
title: "Clients",
nav: true,
settings: {
nav: [
{ href: "#clients/clientsList", title: "Client List" },
{ href: "#clients/Create", title: "Create Client" }
],
auth: true,
roles: ["Employee", "Admin"],
pos: "left"
}
},
{
route: "clients/ClientsList",
name: "clientList",
moduleId: PLATFORM.moduleName(
"../components/clients/clientList/clientList"
),
settings: {
auth: true,
roles: ["Employee", "Admin"]
}
},
{
route: "clients/create",
name: "aboutTeam",
moduleId: PLATFORM.moduleName(
"../components/clients/clientCreate/clientCreate"
),
settings: {
auth: true,
roles: ["Employee", "Admin"]
}
},
{
route: "logout",
name: "logout",
settings: {
icon: "user",
auth: true,
roles: ["Employee", "Admin"],
pos: "right"
},
moduleId: PLATFORM.moduleName("../components/auth/logout/logout"),
nav: true,
title: "Logout"
},
{
route: "not-found",
name: "not-found",
settings: {
auth: true,
roles: ["Employee", "Admin"]
},
moduleId: PLATFORM.moduleName("../components/notFound/notFound"),
nav: false,
title: "Not Found"
},
{
route: "login",
name: "login",
settings: {
icon: "user",
auth: true,
roles: ["Employee", "Admin"],
pos: "right"
},
moduleId: PLATFORM.moduleName("../../public/components/login/login"),
nav: true,
title: "login"
}
]);
config.mapUnknownRoutes("not-found");
}
}
#autoinject
class AuthorizeStep {
private endDate: any;
static loginFragment = '../../public/components/login/login';
constructor(
private authService: AuthService,
private router: Router,
private aurelia: Aurelia
) { }
run(navigationInstruction: NavigationInstruction, next: Next): Promise<any> {
return Promise.resolve()
.then(() => this.checkAuthentication(navigationInstruction, next))
.then(result => result || this.checkAuthorization(navigationInstruction, next))
.then(result => result || this.checkOrigin(navigationInstruction, next))
.then(result => result || next());
}
checkAuthentication(navigationInstruction, next) {
// Do we have a JWT?
const session = this.authService.getIdentity();
if (!session) {
this.forceReturnToPublic(next); // No JWT - back to the public root.
}
console.log("CHECKaUTHENTICATION: ", navigationInstruction.getAllInstructions().some(i => i.config.settings.auth) )
if (navigationInstruction.getAllInstructions().some(i => i.config.settings.auth)) {
// Is the token valid?
if (this.authService.hasTokenExpired(session)) {
const currentUrl = navigationInstruction.fragment + (navigationInstruction.queryString ? `?${navigationInstruction.queryString}` : '');
console.log("FRAGMENT: ", navigationInstruction.fragment);
console.log("NAVIGATE INSTRUCTION: ", navigationInstruction)
console.log('currentURL: ', currentUrl);
localStorage.setItem('origin', currentUrl);
console.log("AuthorizeStep.loginFragment", AuthorizeStep.loginFragment)
next.cancel();
console.log("and it gets here!");
return new Redirect('login');
}
}
}
checkAuthorization(navigationInstruction, next) {
var usersRole = this.authService.getUserRole();
let requiredRoles = navigationInstruction.getAllInstructions()
.map(i => i.config.settings.roles)[0];
console.log("route Roles: ", requiredRoles);
let isUserPermited = requiredRoles ? requiredRoles.some(r => r === usersRole) : true;
console.log("isUserPermited: ", isUserPermited);
if (!isUserPermited) {
this.forceReturnToPublic(next);
}
}
checkOrigin(instruction, next) {
const origin = localStorage.getItem('origin');
// Check if we were not redirected to login page and have an origin
if (instruction.fragment !== AuthorizeStep.loginFragment && origin) {
localStorage.removeItem('origin');
return next.cancel(new Redirect(origin));
}
}
forceReturnToPublic(next) {
if (localStorage.getItem('origin')) {
localStorage.removeItem('origin') // Just in case we had origin set.
}
next.cancel();
this.authService.clearIdentity();
this.router.navigate("/", { replace: true, trigger: false });
this.router.reset();
this.aurelia.setRoot("public/public/public");
}
}
In all other pipeline steps you're using return next.cancel(new Redirect()), it should be the same case, as the pipeline step expects a Next as a return value, but you return a Redirect here.
Try changing it to
return next.cancel(new Redirect('login'));