I have a piece of code (auth.js) that is supposed to be triggered after a user successfully logs in. But I noticed that 2 lines do not seem working. it is not tiggered.
this.$axios.defaults.headers.common['Authorization'] = 'Bearer ' + token;
and
this.$eventHub.$emit('userLoggedIn');
is there something i need to do to make both work? i have set them up to be accessible globally. i checked out the line:
localStorage.setItem('user', JSON.stringify(user));
and seems to work fine.
i have tried remove this word but to no avail.
main.js
import auth from '#/auth'
import axios from 'axios'
Vue.prototype.$axios = axios
Vue.prototype.$auth = auth
Vue.prototype.$eventHub = new Vue();
auth.js
class Auth {
constructor() {
this.token = null;
this.user = null;
}
login(token, user) {
localStorage.setItem('token', token);
localStorage.setItem('user', JSON.stringify(user));
this.$axios.defaults.headers.common['Authorization'] = 'Bearer ' + token;
this.token = token;
this.user = user;
this.$eventHub.$emit('userLoggedIn');
}
check() {
return !! this.token;
}
}
export default new Auth();
this is the code inside my Login.vue which calls the auth.js login method:
login() {
let data = {
email: this.username,
password: this.password
};
this.$axios.post('http://127.0.0.1:8000/api/login', data)
.then(({data}) => {
if (data.status == 200) {
this.$auth.login(data.data.token, data.data.user);
this.$router.replace('about');
} else {
// console.log("Error");
}
})
.catch(() => {
//alert(response.data.message);
});
}
The this keyword in the Auth class is not pointing to the Vue instance. You can pass the Vue instance as a parameter of login method like this:
class Auth {
constructor() {
this.token = null;
this.user = null;
}
login(vue, token, user) {
localStorage.setItem('token', token);
localStorage.setItem('user', JSON.stringify(user));
vue.$axios.defaults.headers.common['Authorization'] = 'Bearer ' + token;
this.token = token;
this.user = user;
vue.$eventHub.$emit('userLoggedIn');
}
check() {
return !! this.token;
}
}
export default new Auth();
And then call login method this way:
this.$auth.login(this, data.data.token, data.data.user);
Related
what I want to achieve is to delete 'accessToken' and 'refreshToken' cookies if both the accessToken and refreshToken are expired and then redirect to '/login' route.
This is my code now
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { verifyAccessToken, verifyRefreshToken } from './utils/checkAuth';
import jwt_decode from "jwt-decode";
import { refreshAccessToken } from './utils/refreshToken';
interface JwtPayload {
email: string
sub: number
iat: number
exp: number
}
export async function middleware(req: NextRequest) {
const accessToken = req.cookies.get('accessToken')?.value;
const refreshToken = req.cookies.get('refreshToken')?.value;
if(accessToken && refreshToken){
const jwtPayload: JwtPayload = jwt_decode(accessToken);
const validToken =
accessToken &&
(await verifyAccessToken(accessToken).catch((err) => {
console.log(err);
}));
if(req.nextUrl.pathname.startsWith('/login') && !validToken){
return
}
if((req.url.includes('/login') || req.url.includes('/register')) && validToken){
return NextResponse.redirect(new URL('/login', req.url));
}
if(!validToken){
try {
const validRefreshToken =
refreshToken &&
(await verifyRefreshToken(refreshToken).catch((err) => {
console.log(err);
}));
if(validRefreshToken){
const newAccessToken = await refreshAccessToken(refreshToken, jwtPayload?.sub);
console.log('GENERATED NEW ACCESS TOKEN', newAccessToken);
// here I want to set accesToken cookie to newAccessToken
} else {
console.log('Refresh token expired');
throw new Error('Refresh token expired')
}
} catch (error) {
console.log('cookies should be deleted');
return NextResponse.redirect(new URL('/login', req.url));
}
}
console.log('TOKEN VALID', accessToken);
} else {
if(req.nextUrl.pathname.startsWith('/login')){
return
} else {
return NextResponse.redirect(new URL('/login', req.url));
}
}
}
// See "Matching Paths" below to learn more
export const config = {
matcher: ['/', '/login', '/register', '/jobs/:path*', '/profile'],
}
I found out that by doing this
const response = NextResponse.next()
response.cookies.delete('accessToken')
response.cookies.delete('refreshToken')
this will work but then for this to actually delete the cookies I need to return "response" from the middleware but I also want to redirect the user to "/login" and this does not happen if I return "response" instead of returning the "NextResponse.redirect(new URL('/login', req.url))"
How can I remove the cookies or set the cookies and then also redirect ?
I am using NestJS and its JWT package based on jsonwebtoken. The generated token is always being invalid, and I am getting a 500 - Internal Server Error.
What might be the problem?
My login function in the AuthService:
async login(email: string, password: string, isAdmin?: boolean, isVIP?: boolean){
let user = await this.usersService.findByEmail(email);
if(!user){
throw new NotFoundException('No user with this email could be found.');
}
const isEqual = await bcrypt.compare(password, user.password);
if(!isEqual){
throw new BadRequestException('Email and password do not match');
}
const secret = 'secretkey';
const payload = {email: user.email, userId: user._id.toString()}
const token = this.jwtService.sign(payload, {secret, expiresIn: '1h'});
return [email, isAdmin, isVIP, token];
}
My verification logic in the AuthGuard
`
import { BadRequestException, CanActivate, ExecutionContext, Inject } from "#nestjs/common";
import { JwtService } from "#nestjs/jwt/dist";
import { JwtConfigService } from "src/config/jwtconfig.service";
export class JwtAuthGuard implements CanActivate {
constructor(#Inject(JwtService) private jwtService: JwtService){}
canActivate(context: ExecutionContext) {
const request = context.switchToHttp().getRequest();
const authHeader = request.get('Authorization');
if (!authHeader) {
throw new BadRequestException('Not authorized');
}
const token = authHeader.split(' ')[1];
let decodedToken;
try {
decodedToken = this.jwtService.verify(token, {secret: 'secretkey'});
} catch (err) {
throw new Error('Cannot verify token.')
}
if(!decodedToken){
throw new BadRequestException('Not authenticated')
}
request.userId = decodedToken.userId;
console.log({decodedToken, token});
return request.userId;
};
}
My current JWT setup in the UsersModule imports (I have no AuthModule); I tried all the other configurations in the official docs, too.
JwtModule.register({
secret: 'secretkey',
publicKey: '...',
privateKey: '...',
secretOrKeyProvider: (
requestType: JwtSecretRequestType,
tokenOrPayload: string | Object | Buffer,
verifyOrSignOrOptions?: jwt.VerifyOptions | jwt.SignOptions
) => {
switch (requestType) {
case JwtSecretRequestType.SIGN:
return 'privateKey';
case JwtSecretRequestType.VERIFY:
return 'publicKey';
default:
return 'secretkey';
}
},
})
`
My jwtconfig.ts, which I don't think is being used:
`
import { JwtOptionsFactory, JwtModuleOptions } from '#nestjs/jwt'
export class JwtConfigService implements JwtOptionsFactory {
createJwtOptions(): JwtModuleOptions {
return {
secret: 'secretkey'
};
}
}
`
I solved the problem by switching my guard to a middleware.
Problem:
In my react native app in order to remove repeated calls I have developed a general POST GET methods in httpClient file. It code is look likes this.
import axios from 'axios';
import AsyncStorage from '#react-native-community/async-storage';
axios.defaults.headers.post['Content-Type'] = 'application/json';
var instance = null;
const setAuthorisationHeder = async () => {
const token = JSON.parse(await AsyncStorage.getItem('auth_data'));
if (token) {
console.log('>>>>>> instance', instance);
Object.assign(instance.headers, {
Authorization: 'Bearer' + token.accessToken,
});
} else {
console.log('>>>>>> instance', instance);
Object.assign(instance.headers, {
Authorization: '',
});
}
};
export const setHeader = () => {
console.log('>>>>>>>> HIIII');
instance = axios.create({
baseURL: '',
timeout: 150000,
headers: {
'Content-Type': 'application/json',
},
});
instance.interceptors.response.use(
function (response) {
return response;
},
async function (error) {
if (error.response.status) {
if (error.response.status === 401) {
AsyncStorage.removeItem('auth_data');
} else {
throw error;
}
} else {
console.log(error);
}
},
);
};
export const Get = (route, data) => {
function getData() {
return instance.get(
route,
data == null ? {data: {}} : {data: JSON.stringify(data)},
);
}
if (instance) {
console.log('>>>>>> HIIIIii');
// setAuthorisationHeder();
return getData();
}
return setHeader().then(getData);
};
export const Post = (route, data) => {
console.log('>>>>>> route', route);
function postData() {
return instance.post(route, JSON.stringify(data));
}
if (instance) {
console.log('>>>>>> HIIIIii');
// setAuthorisationHeder();
// setAuthorisationHeder();
return postData();
}
return setHeader().then(postData);
};
Can some tell me a way to add an authorization header to this instance? My token is storing the Asyncstorage in the middle of some actions so at the beginning called I don't have the token. As my code setHeader is running only one time so I created a method call setAuthorisationHeder() function. But it is giving me can not find property .then error when I am putting a request. Can someone help me to solve this issue? Thank you?
you can define global headers once and use it in every network call.
https://github.com/axios/axios#global-axios-defaults
Create a global auth variable where you'll store the auth data from storage. Before making a request get the auth data and use interceptor to set the bearer token.
let authToken = '';
const getAuthToken = async () => {
// asumming auth token was saved as string
authToken = await AsyncStorage.getItem('auth_data');
};
Interceptor
// request interceptor
axiosInstance.interceptors.request.use(
function (config) {
// Do something before request is sent
config.headers.Authorization = `Bearer ${authToken}`;
return config;
},
function (error) {
// Do something with request error
return Promise.reject(error);
}
);
complete code
import axios from 'axios';
import AsyncStorage from '#react-native-community/async-storage';
let authToken = '';
const axiosInstance = axios.create({
baseURL: '',
timeout: 150000,
headers: {
'Content-Type': 'application/json',
},
});
// request interceptor
axiosInstance.interceptors.request.use(
function (config) {
// Do something before request is sent
config.headers.Authorization = `Bearer ${authToken}`;
return config;
},
function (error) {
// Do something with request error
return Promise.reject(error);
}
);
const getAuthToken = async () => {
// asumming auth token was saved as string
authToken = await AsyncStorage.getItem('auth_data');
};
export const Get = async (route, data = {}) => {
// get and set auth token
await getAuthToken();
// route = /user?id=787878 or /user/787878
return await axiosInstance.get(route);
};
export const Post = async (route, data = {}) => {
await getAuthToken();
return await axiosInstance.post(route, data);
};
I am working on a SPA, I have used JWT authentication for a login system. on the local server its working fine, I mean when I click login I get the token etc and store on local storage and it redirects me to dashboard everything perfect.
but on a live server, I get the token but it doesn't store it on local storage.
I am completely lost. I tried everything but still. please help me with this.
it's my first time with the SPA so I am not sure what I am missing.
Login Method
login(){
User.login(this.form)
}
User.js
import Token from './Token'
import AppStorage from './AppStorage'
class User {
login(data) {
axios.post('/api/auth/login', data)
.then(res => this.responseAfterLogin(res))
.catch(error => console.log(error.response.data))
}
responseAfterLogin(res) {
const access_token = res.data.access_token
const username = res.data.user
if (Token.isValid(access_token)) {
AppStorage.store(username, access_token)
window.location = '/me/dashboard'
}
}
hasToken() {
const storedToken = AppStorage.getToken();
if (storedToken) {
return Token.isValid(storedToken) ? true : this.logout()
}
return false
}
loggedIn() {
return this.hasToken()
}
logout() {
AppStorage.clear()
window.location = '/me/login'
}
name() {
if (this.loggedIn()) {
return AppStorage.getUser()
}
}
id() {
if (this.loggedIn()) {
const payload = Token.payload(AppStorage.getToken())
return payload.sub
}
}
own(id) {
return this.id() == id
}
admin() {
return this.id() == 1
}
}
export default User = new User();
Token.js
class Token {
isValid(token){
const payload = this.payload(token);
if(payload){
return payload.iss == "http://127.0.0.1:8000/api/auth/login" ? true : false
}
return false
}
payload(token){
const payload = token.split('.')[1]
return this.decode(payload)
}
decode(payload){
return JSON.parse(atob(payload))
}
}
export default Token = new Token();
AppStorage.js
class AppStorage {
storeToken (token) {
localStorage.setItem('token', token);
}
storeUser (user) {
localStorage.setItem('user', user);
}
store (user, token) {
this.storeToken(token)
this.storeUser(user)
}
clear () {
localStorage.removeItem('token')
localStorage.removeItem('user')
}
getToken () {
return localStorage.getItem('token')
}
getUser () {
return localStorage.getItem('user')
}
}
export default AppStorage = new AppStorage()
Thanks
I am new to vue and stuck on this problem for quite some time. I have a login method that retrieves an API token and stores it in localStorage. The login API call is the only call that does not send Auth headers. After the Login every call should add the API token to the header.
When I login the interceptor does not set the new header. It needs a page refresh in the browser to work. Why is that, what am I doing wrong?
In my Login component I have this method:
methods: {
login() {
api.post('auth/login', {
email: this.email,
password: this.password
})
.then(response => {
store.commit('LOGIN');
localStorage.setItem('api_token', response.data.api_token);
});
this.$router.push('reservations')
}
}
Additionally I have this axios base instance and an interceptor:
export const api = axios.create({
baseURL: 'http://backend.local/api/',
// headers: {
// 'Authorization': 'Bearer ' + localStorage.getItem('api_token')
// },
validateStatus: function (status) {
if (status == 401) {
router.push('/login');
} else {
return status;
}
}
});
api.interceptors.request.use((config) => {
config.headers.Authorization = 'Bearer ' + localStorage.getItem('api_token');
return config;
}, (error) => {
return Promise.reject(error);
});