Authentication with axios throwing internal server error in Next JS - javascript

Getting 500 internal server error for my next authentication.
I implemented everything according to the docs from Next Auth.
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import axios from "axios";
import { API_URL } from "./../../../helpers/api/mutations";
const options = {
providers: [
CredentialsProvider({
name: "Credentials",
API works fine in a separate react component but fails only on Next Auth.
async authorize(credentials) {
const user = axios({
url: API_URL,
method: "post",
data: {
query: `mutation($mobileNumber:String,$mobileCountryCode:String,$otp:Int){
verifyPhoneOTP(
mobileNumber: $mobileNumber,
mobileCountryCode: $mobileCountryCode,
otp:$otp
)
{accessToken
expiresAt}
}`,
variables: {
mobileNumber: credentials.mobile,
mobileCountryCode: credentials.email,
otp: credentials.otpFormatt,
},
},
validateStatus: (status) => {
if (status == 500) {
console.log(status, "status axios log");
console.log(credentials, "credentials log");
return true;
}
},
headers: {
"User-Agent":
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36",
Accept: "application/json; charset=UTF-8",
},
})
.catch((error) => {
console.log(error.response.data, "axios fail calls");
})
.then((result) => {
Currently I can see this console log "axios calls" successfully displays itself on the terminal but the tokens and sessions aren't returned.
console.log(result.data, "axios calls");
console.log(credentials, "creds");
return result.data.data
});
if (user) {
return user;
} else {
return null;
}
},
}),
],
};
const callbacks = {
async jwt(token, user) {
if (user) {
token.accessToken = user.token;
}
return token;
},
secret:process.env.SECRET,
async session(session, token) {
session.accessToken = token.accessToken;
return session;
},
};
export default (req, res) => NextAuth(req, res, options);

Error 500 means server error. Check you api server whether it is running or stopped. Error 500 here has nothing to do with nextjs, it is all about the back-end server.

Related

HttpOnly cookies are not sent with request to server

I've created API in node express and I'm running it on port :8000, I am consuming APIs through simple CRA on port :3000. I've created registration and login with setting httpOnly cookie. Furthermore, I've put middleware to check each endpoint in order to verify if it has that token.
When I test through Thunder/Postman everything works, after logging in I get the cookie in response, I set that cookie as auth token and make request to get data and I get the data.
When I log in through the React Frontend it succeeds and I can see in network tab that I have received the cookie in response. But when I make a request to protected endpoint, the request does not have a cookie in it (I log incoming requests on server and compare ones made with Thunder/Postman client and via app in Browser).
I use axios, and I've put {withCredentials: true} it doesn't work. I've used withAxios hook and it doesn't work either.
SERVER
index.js
...
const app = express()
app.use(cors({
credentials: true,
origin: 'http://localhost:3000',
}));
...
controllers/User.js
...
const loginUser = async(req, res) => {
const body = req.body
const user = await User.findOne({ email: body.email })
if(user) {
const token = generateToken(user)
const userObject = {
userId: user._id,
userEmail: user.email,
userRole: user.role
}
const validPassword = await bcrypt.compare(body.password, user.password)
if(validPassword) {
res.set('Access-Control-Allow-Origin', req.headers.origin);
res.set('Access-Control-Allow-Credentials', 'true');
res.set(
'Access-Control-Expose-Headers',
'date, etag, access-control-allow-origin, access-control-allow-credentials'
)
res.cookie('auth-token', token, {
httpOnly: true,
sameSite: 'strict'
})
res.status(200).json(userObject)
} else {
res.status(400).json({ error: "Invalid password" })
}
} else {
res.status(401).json({ error: "User doesn't exist" })
}
}
...
middleware.js
...
exports.verify = (req, res, next) => {
const token = req.headers.authorization
if(!token) res.status(403).json({ error: "please provide a token" })
else {
jwt.verify(token.split(" ")[1], tokenSecret, (err, value) => {
if(err) res.status(500).json({error: "failed to authenticate token"})
req.user = value.data
next()
})
}
}
...
router.js
...
router.get('/bills', middleware.verify, getBills)
router.post('/login', loginUser)
...
CLIENT
src/components/LoginComponent.js
...
const loginUser = (e) => {
setLoading(true)
e.preventDefault()
let payload = {email: email, password: password}
axios.post('http://localhost:8000/login', payload).then(res => res.status === 200
? (setLoading(false), navigate('/listbills')) : navigate('/register'))
}
...
src/components/ListBills.js
...
useEffect(() => {
fetch('http://localhost:8000/bills', {
method: 'get',
headers: {'Content-Type': 'application/json'},
credentials: 'include',
})
.then(response => {console.log(response)}).catch(err => console.log(err));
}, [])
...
I've also tried:
axios.get('http://localhost:8000/bills',{withCredentials: true})
.then((data) => console.log(data))
.then((result) => console.log(result))
.catch((err) => console.log('[Control Error ] ', err))
}
and
const [{ data, loading, error }, refetch] = useAxios(
'http://localhost:8000/bills',{
withCredentials: true,
headers: {'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json'
}})
Console.log error:
After I login I get this in Network tab:
However when I want to access the list:
=== UPDATE ===
So the cause of the issue is not having the httpOnly cookie passed in the request header. This is the log of the middleware I am using:
token undefined
req headers auth undefined
req headers {
host: 'localhost:8000',
connection: 'keep-alive',
'sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36',
'sec-ch-ua-platform': '"macOS"',
'content-type': 'application/json',
accept: '*/*',
origin: 'http://localhost:3000',
'sec-fetch-site': 'same-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'http://localhost:3000/',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'en-US,en;q=0.9,hr;q=0.8,sr;q=0.7,bs;q=0.6,de;q=0.5,fr;q=0.4,it;q=0.3'
}
token is read from headers.authorization but from the log of the headers it doesn't exist so my requests fail to be authorized.
Still not working.
After reading everything on CORS and httpOnly cookies I've managed to get it working.
First I removed sameSite and added domain prop according to documentation in controllers/User.js on SERVER
res.cookie('auth-token', token, {
httpOnly: true,
domain: 'http://localhost:3000'
})
Then I got a little yellow triangle in the console request view, it said that domain was invalid. Then I just changed domain to origin and the cookie appeared in the request log of the headers 🎉
res.cookie('auth-token', token, {
httpOnly: true,
origin: 'http://localhost:3000',
})
The cookie was not in the Authorization property of the headers but in the cookie so I had to change the code in the middleware.js since it expected format bearer xxyyzz but receiving auth-token=xxyyzz, it looks like this now:
exports.verify = (req, res, next) => {
const token = req.headers.cookie
if(!token) res.status(403).json({ error: "please provide a token" })
else {
jwt.verify(token.split("=")[1], tokenSecret, (err, value) => {
if(err) res.status(500).json({error: "failed to authenticate token"})
req.user = value.data
next()
})
}
}

Nodejs .Unable to send oauth v1 params in get request with axios

I wanted to make a request to ADP with autho1.0a
I was able to make successful requests as I wanted in postman but not through my application.
postman screenshot
npm module used
similar post
Code I tried
Part:1 Signature generation
const crypto = require('crypto')
const OAuth = require('oauth-1.0a')
const oauthObj = {};
function hash_function_sha1(base_string, key) {
return crypto
.createHmac('sha1', key)
.update(base_string)
.digest('base64')
}
oauthObj.getSignature = async payload => {
const { consumerKey,consumerSecret,apiUrl,method} = payload;
const oauth = OAuth({
consumer: { key: `${consumerKey}`, secret: `${consumerSecret}` },
signature_method: 'HMAC-SHA1',
hash_function: hash_function_sha1,
});
const request_data = {
url: `${apiUrl}`,
method: `${method}`
}
const token = {}
// return oauth.toHeader(oauth.authorize(request_data, token));
console.log('header string-----',oauth.toHeader(oauth.authorize(request_data, token)));
return oauth.authorize(request_data, token);
}
module.exports = oauthObj;
Part 2 : Axios Call
let oauthData=`oauth_consumer_key=${consumerKey}&oauth_signature_method=HMAC-SHA1&oauth_timestamp=${oauthTimestamp}&oauth_nonce=${oauthNonce}&oauth_version=1.0&oauth_signature=${oauthSignature}= HTTP/1.1`;
const eventData = await axios({
url:`${apiUrl}?${oauthData}`,
// url:`${apiUrl}?${oauthHeader.Authorization}`,
method:'GET',
headers:{
// ...oauthHeader,
'Authorization':'OAuth',
'Accept': 'application/json',
// "Authorization": `'OAuth oauth_consumer_key="${consumerKey}", oauth_nonce="${oauthNonce}", oauth_signature="${oauthSignature}", oauth_signature_method="HMAC-SHA1", oauth_timestamp="${oauthTimestamp}", oauth_version="1.0"`
}
});
Expected Result:
{
"code": "Gone",
"message": "Event with token 954c183f-26e0-4f9e-b452-c089aaf9842f has already been consumed."
}
Receiving error:
response: {
status: 401,
statusText: 'Unauthorized',
headers: {
What might have gone wrong ?
Try using request node package oauth option
request.get(`${apiUrl}?${oauthData}`, {
oauth: {
consumer_key: '..',
consumer_secret: '..',
},
headers: {
Accept: 'application/json'
},
}, function (err, res, body) {
console.log(body);
})

Vue-Auth issue in setting token to header['authorization']

I am having an issue in setting the authorization token to the request header. I always get a 401 Unathuroized issue after setting my header using a bearer driver. Below is my code:
bearer.js
module.exports = {
request: function (req, token) {
this.options.http._setHeaders.call(this, req, {Authorization: 'Bearer ' + token})
},
response: function (res) {
if (res.data.token) {
return res.data.token
}
}
}
main.js
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
import VueAuth from '#websanova/vue-auth'
Vue.use(VueAuth, {
auth: require('#websanova/vue-auth/drivers/auth/bearer.js'),
http: require('#websanova/vue-auth/drivers/http/axios.1.x.js'),
router: require('#websanova/vue-auth/drivers/router/vue-router.2.x.js'),
refreshData: {url: 'auth/refresh', method: 'GET', enabled: false, interval: 30},
fetchData: {url: 'auth/user', method: 'GET', enabled: false},
notFoundRedirect: {path: '/admin'},
rolesVar: 'roles',
})
and the code in login.vue
this.$auth.login({
data: credentials,
url: process.env.VUE_APP_URL + '/api/v1/login',
fetchUser: false,
success: function (response) {
if(response.data){
localStorage.setItem('user',(JSON.stringify(response.data.data)));
this.$auth.user(response.data.data);
this.$auth.watch.authenticated = true;
this.$auth.watch.loaded = true;
this.$router.push('/dashboard');
axios.defaults.headers.common["Authorization"] = "Bearer " + response.data.data.token;
debugger;
}
},
error: function () {
this.$notify({
type: 'warn',
title: 'Login',
text: 'Login failed'
});
},
})
I tried to add a debugger inside the request method of a bearer.js driver, that doesn't seem to execute.

token is missing in my vue app

I have this response with httpie when an user is logged:
chat-api$ http :3000/signup username=tomatito password=123
HTTP/1.1 201 Created
Cache-Control: max-age=0, private, must-revalidate
Content-Type: application/json; charset=utf-8
ETag: W/"01dfe24bd7415e252b5aee50e12198a3"
Transfer-Encoding: chunked
Vary: Origin
X-Request-Id: a095148b-592a-4347-820f-63e1efa0e409
X-Runtime: 0.347726
{
"auth_token": "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo1LCJleHAiOjE1MjEzMTg4NDV9.45JDA7vk-K8gUzCB1xABKMifi-IWGoVESedKykGiqGo",
"message": "Account created successfully"
}
The object is persisted in my database.
However when i make this request with axios from my vue.js form I get nothing in localStorage
this is my axios.js code:
import axios from 'axios'
const API_URL = process.env.API_URL || 'http://localhost:3000/'
export default axios.create({
baseURL: API_URL,
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + localStorage.auth_token
}
})
the object is persisted in database right but i get Authorization:Bearer undefined
these are my headers:
Response:
Access-Control-Allow-Methods:GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD
Access-Control-Allow-Origin:http://localhost:8081
Access-Control-Expose-Headers:
Access-Control-Max-Age:1728000
Cache-Control:max-age=0, private, must-revalidate
Content-Type:application/json; charset=utf-8
ETag:W/"fdac439f3ada9e343d0815bb49dff277"
Transfer-Encoding:chunked
Vary:Origin
X-Request-Id:9e318050-ceca-480c-a847-d59f9ebb18b7
X-Runtime:0.447976
Request:
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.9
Authorization:Bearer undefined
Connection:keep-alive
Content-Length:44
Content-Type:application/json
Host:localhost:3000
Origin:http://localhost:8081
Referer:http://localhost:8081/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.
Request payload
{username: "tomatito", password: "123456"}
password:"123456"username:"tomatito"
This is my vue script component:
<script>
export default {
name: 'SignUp',
data () {
return {
username: '',
password: '',
error: false
}
},
methods: {
signup () {
this.$http.post('/signup', { username: this.username, password: this.password })
.then(request => this.signupSuccessful(request))
.catch(() => this.signupFailed())
},
signupSuccessful (req) {
if (!req.data.token) {
this.signupFailed()
return
}
localStorage.token = req.data.token
this.error = false
this.$router.replace(this.$route.query.redirect || '/rooms')
},
signupFailed () {
this.error = 'Sign up failed!'
delete localStorage.token
}
}
}
</script>
I'm getting Sign up failed, However the object is persisted in database. My back-end is ruby on rails. How can i receive in my data.token in payload?
This is my main.js file
import Vue from 'vue'
import App from './App'
import router from './router'
import axios from './backend/vue-axios'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
axios,
template: '<App/>'
})
This is my vue-axios/index.js file:
import Vue from 'vue'
import VueAxios from 'vue-axios'
import axios from './axios'
Vue.use(VueAxios, axios)
Updated The problem was in req. it's res to receive the token instead of req
signup() {
this.$http
.post("/signup", { username: this.username, password: this.password })
.then(res => this.signupSuccessful(res))
.catch(() => this.signupFailed());
},
signupSuccessful(res) {
if (!res.data.auth_token) {
this.signupFailed();
return;
}
this.error = false;
localStorage.token = res.data.auth_token;
this.$store.dispatch("login");
this.$router.replace(this.$route.query.redirect || "/rooms");
},
.
.
.
.
Thank you
Try to set the token on every request with axios.interceptors
Put this on the main.js file so everywhere you import axios will have the config
axios.interceptors.request.use(config => {
const token= localStorage.getItem('my-token-key') // or where you have the token
config.headers.common['Authorization'] = 'Bearer ' + token
// you must return the config or it will not work
return config
})
I think that the problem is that axios.create instance is executed (created) just 1 time (then reference it), and not every time you import it, so if there was no token when the instance was created it will not work
Updated The problem was in req. it's res to receive the token instead of req
signup() {
this.$http
.post("/signup", { username: this.username, password: this.password })
.then(res => this.signupSuccessful(res))
.catch(() => this.signupFailed());
},
signupSuccessful(res) {
if (!res.data.auth_token) {
this.signupFailed();
return;
}
this.error = false;
localStorage.token = res.data.auth_token;
this.$store.dispatch("login");
this.$router.replace(this.$route.query.redirect || "/rooms");
},
.
.
.
.

Node request how to handle sessions

I'm using node.JS with request module.
My problem is, I need to authenticate the user on every request because the session is destroyed outside of the .then((response) => {}) block.
How is it possible to save the created session in a class for later use?
I tried out everything without success.
Here is a not working code snippet
login() {
const getLoginUrl = 'https://www.demourl.com/'
const postLoginUrl = 'https://www.demourl.com/account/login/'
rp({
url: getLoginUrl,
jar: this.cookieJar,
method: 'GET'
})
.then((body) => {
var csrftoken = this.cookieJar.getCookies(getLoginUrl)[1].toString().split('=')[1].split(';')[0];
var args = {
url: postLoginUrl,
json: true,
method: 'POST',
data: {
username: this.username,
password: this.password
},
headers: {
'method': 'POST',
'path': '/account/login/',
'cookie': 'csrftoken=' + csrftoken,
},
jar: this.cookieJar,
resolveWithFullResponse: true
}
rp(args)
.then((response) => {
//Here is a valid session
//But how can I use this session in different functions?
console.log('Post demourl.com/account/login success');
})
.catch((error) => {
console.log('Post demourl.com/account/login error: ', error);
});
})
.catch((error) => {
console.log('Get demourl.com error: ', error);
});
}
you should use this function as a middleware and then attach what ever you want to attach in to your req
try in you main script do
'use strict'
const express = require('express');
const login = require('./login');
const app = express()
app.use(login);// use this if you want all your routes to check login or put it in a specific route
app.get('/', (req,res)=>{
//this route is only for loged in users
});
const server = http.createServer(app).listen(process.env.PORT);
module.exports = app;
and in your login script
const login = (req, res, next) => {
const getLoginUrl = 'https://www.demourl.com/'
const postLoginUrl = 'https://www.demourl.com/account/login/'
rp({url: getLoginUrl, jar: this.cookieJar, method: 'GET'})
.then((body) => {
var csrftoken = this.cookieJar.getCookies(getLoginUrl)[1].toString().split('=')[1].split(';')[0];
var args = {
url: postLoginUrl,
json: true,
method: 'POST',
data: {
username: this.username,
password: this.password
},
headers: {
'method': 'POST',
'path': '/account/login/',
'cookie': 'csrftoken=' + csrftoken,
},
jar: this.cookieJar,
resolveWithFullResponse: true
}
rp(args)
.then((response) => {
res.loginResponse = response; // save the response for later use
console.log('Post demourl.com/account/login success');
next();
})
.catch((error) => {
console.log('Post demourl.com/account/login error: ', error);
return res.send(error) //send the error
});
})
.catch((error) => {
console.log('Get demourl.com error: ', error);
return res.send(error) //send the error
});
}
module.exports = login
I never see this.cookieJar being defined. Make sure it's initialized somewhere:
this.cookieJar = request.jar();
If you only use a single cookieJar in your application, you could also use Request's global cookie jar by setting the option jar to true:
// Either by setting it as the default
const request = require('request').defaults({jar: true});
// Or by setting it on each request
request('www.example.com', { jar: true });

Categories

Resources