I'm making a Rest Api with Node.js, but I have no idea of how to put information on headers and receive it in another endpoint, in this case, I want to send the token signed in headers to get it in another endpoint with a require.headers
So, What's the method I should use? and if you have an explanation is better.
const { Router } = require("express");
const router = Router();
const jwt = require('jsonwebtoken');
const authmiddleware = require('../Middlewares/auth.middleware')
router.get("/kiral/jwt", (req, res) => {
const token = jwt.sign({
data: "informacion importante"
}, 'seed', {expiresIn: '1h' });
res.json({
message: "Hello endpoint jwt",
token
});
});
If you want to send the token information in the response headers you do something like this
const { Router } = require("express");
const router = Router();
const jwt = require('jsonwebtoken');
const authmiddleware = require('../Middlewares/auth.middleware')
router.get("/kiral/jwt", (req, res) => {
const token = jwt.sign({
data: "informacion importante"
}, 'seed', {expiresIn: '1h' });
res.header('token', token); // this will be sent in response headers
res.json({
message: "Hello endpoint jwt",
token
});
});
Related
I'm creating a Discord login, but when I get redirected, I get the error. The error happens after I press authorize on the Discord OAuth page
{"status":"ERROR","error":"Response code 400 (Bad Request)"}
Here is my code for Discord.js
const express = require('express');
const router = express.Router();
const fetch = require('got');
const btoa = require('btoa');
const { catchAsync } = require('../utils');
const CLIENT_ID = '#';
const CLIENT_SECRET = '#';
const redirect = encodeURIComponent('https://ezapplications.live/api/discord/callback');
router.get('/callback', catchAsync(async (req, res) => {
if (!req.query.code) throw new Error('NoCodeProvided');
const response = await fetch(`https://discordapp.com/api/oauth2/authorize?client_id=${CLIENT_ID}&scope=identify&response_type=code&redirect_uri=${redirect}`, {
method: 'POST',
body: new URLSearchParams({
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
grant_type: "authorization_code",
redirect_uri: "https://ezapplications.live/api/discord/callback",
code: req.query.code
})
});
const json = await response.json();
res.redirect(`/?token=${json.access_token}`);
}));
router.get('/login', (req, res) => {
res.redirect(`https://discordapp.com/api/oauth2/authorize?client_id=${CLIENT_ID}&scope=identify&response_type=code&redirect_uri=${redirect}`);
});
module.exports = router;
Here is my code for Server.js
const express = require('express');
const path = require('path');
const app = express();
app.get('/', (req, res) => {
res.status(200).sendFile(path.join(__dirname, 'index.html'));
});
app.use('/api/discord', require('./api/discord'));
app.use((err, req, res, next) => {
switch (err.message) {
case 'NoCodeProvided':
return res.status(400).send({
status: 'ERROR',
error: err.message,
});
default:
return res.status(500).send({
status: 'ERROR',
error: err.message,
});
}
});
app.listen(50451, () => {
console.info('Running on port 50451');
});
Here is the code for utils.js
// async/await error catcher
const catchAsyncErrors = fn => (
(req, res, next) => {
const routePromise = fn(req, res, next);
if (routePromise.catch) {
routePromise.catch(err => next(err));
}
}
);
exports.catchAsync = catchAsyncErrors;
I'm not sure why I get this error as everything seems fine to me, thanks.
As per the Authorization Code Grant docs, you need to pass the parameters in the request body instead of the query string.
const response = await fetch("https://discord.com/api/oauth2/token", {
method: 'POST',
headers: {
"content-type": "application/x-www-form-urlencoded"
},
body: new URLSearchParams({
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
grant_type: "authorization_code",
redirect_uri: "https://ezapplications.live/api/discord/callback",
code: req.query.code
}).toString()
});
Regarding HTTP Basic auth...
You can also pass your client_id and client_secret as basic authentication with client_id as the username and client_secret as the password
...but I don't really see the point. Your choice
When I make a post request to the /login endpoint in postman it works fine and returns all the information. However when I try to navigate to the end point in the url the route returns unfound. In the console I get GET http://localhost:5000/login 404 (Not Found). Why is the console returning for a get request? If I try to call the post request in axios I get xhr.js:177 POST http://localhost:3000/login 404 (Not Found).
app.js
require("dotenv").config();
const express = require('express');
const morgan = require('morgan');
const bodyParser = require('body-parser');
const router = express.Router();
const cors = require('cors');
const app = express();
app.use(cors())
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
const mongoose = require('mongoose');
const connection = "password"
mongoose.connect(connection, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true
})
const clientRoutes = require('./routes/clientRoutes');
const traderRoutes = require('./routes/traderRoutes');
const loginRoute = require('./routes/loginRoute')
app.use('/', clientRoutes, traderRoutes, loginRoute);
// setup a friendly greeting for the root route
app.get('/', (req, res) => {
res.json({
message: 'Welcome to the REST API for Pave!',
});
});
// send 404 if no other route matched
app.use((req, res) => {
res.status(404).json({
message: 'Route Not Found',
});
});
// setup a global error handler
app.use((err, req, res, next) => {
if (enableGlobalErrorLogging) {
console.error(`Global error handler: ${JSON.stringify(err.stack)}`);
}
res.status(err.status || 500).json({
message: err.message,
error: {},
});
});
app.listen(5000, () => console.log('Listening on port 5000!'))
loginRoute.js
require("dotenv").config();
const express = require("express");
const router = express.Router();
const jwt = require("jsonwebtoken");
const bcryptjs = require("bcryptjs");
const Client = require("../models/clientSchema");
const Trader = require("../models/traderSchema");
function asyncHandler(callback) {
return async (req, res, next) => {
try {
await callback(req, res, next);
} catch (error) {
next(error);
console.log(error);
}
};
}
router.post('/login', asyncHandler(async (req, res, next) => {
let user = req.body;
const trader = await Trader.findOne({ emailAddress: req.body.emailAddress })
if (user && trader) {
console.log(trader)
let traderAuthenticated = await bcryptjs.compareSync(user.password, trader.password);
console.log(traderAuthenticated)
if (traderAuthenticated) {
console.log('Trader match')
const accessToken = jwt.sign(trader.toJSON(), process.env.ACCESS_TOKEN_SECRET)
res.location('/trader');
res.json({
trader: trader,
accessToken: accessToken
}).end();
} else {
res.status(403).send({ error: 'Login failed: Please try again'}).end();
}
} else if (user && !trader) {
const client = await Client.findOne({emailAddress: req.body.emailAddress})
console.log(client)
let clientAuthenticated = await bcryptjs.compareSync(user.password, client.password);
console.log(clientAuthenticated)
if (clientAuthenticated) {
console.log('Client match')
const accessToken = jwt.sign(client.toJSON(), process.env.ACCESS_TOKEN_SECRET)
res.location('/client');
res.json({
client: client,
accessToken: accessToken
});
} else {
res.status(403).send({ error: 'Login failed: Please try again'}).end();
}
} else {
res.status(403).send({ error: 'Login failed: Please try again'}).end();
}
})
);
module.exports = router;
You set POSTMAN to make a POST request, right? When you enter a url in the browser, that causes a GET request - and you have no route to manage this that I can see, but for the default Not found.
you are calling with axios with wrong port no. it should, POST method http://localhost:5000/login as your application is running on port 5000.
but you are calling, POST http://localhost:3000/login
I wrote a small node.js server with a login system and I am trying to protect my routes. I have created the middleware that should check authentication on each protected route, but it seems that I am not sending the JWT token correctly, because every time I log in I get the Authentication failed message. How can I send the JWT token correctly and log in if the password and username are correct? Here is my Node.js server:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const mongoose = require('mongoose');
require('dotenv').config();
const PORT = process.env.PORT || 1337;
const jwt = require('jsonwebtoken');
const checkAuth = require('./middleware/check-auth.js')
let Post = require('./models/post.model.js');
app.use(cors());
app.use("/assets", express.static(__dirname + "/assets"));
app.use(bodyParser.urlencoded({ extended: true }));
app.set('view-engine', 'ejs');
app.get('/', (req, res) => {
res.render('index.ejs');
});
app.post('/', (req, res) => {
let username = req.body.username;
let password = req.body.password;
if (username !== process.env.USER_NAME && password !== process.env.USER_PASSWORD) {
res.json('Invalid credentials');
} else {
const token = jwt.sign({
username: username,
}, process.env.SECRET_KEY, {
expiresIn: '1h'
});
res.redirect(`/dashboard?token=${token}`);
}
});
app.get('/dashboard', checkAuth, (req, res) => {
res.render('dashboard.ejs');
});
app.get('/dashboard/createPost', checkAuth, (req, res) => {
res.render('post.ejs');
});
app.post('/dashboard/createPost', async (req, res) => {
let collection = connection.collection(process.env.POSTS_WITH_TAGS);
res.setHeader('Content-Type', 'application/json');
let post = new Post(req.body);
collection.insertOne(post)
.then(post => {
res.redirect('/dashboard')
})
.catch(err => {
res.status(400).send(err);
});
});
app.listen(PORT);
and here is my check-auth middleware:
const jwt = require('jsonwebtoken');
module.exports = (req, res, next) => {
try {
const token = req.headers.authorization.split(' ')[1];
console.log(token);
const decoded = jwt.verify(token, process.env.SECRET_KEY, null);
req.body.decoded = decoded;
console.log(req.body.decoded);
} catch (error) {
return res.status(401).json({
message: 'Authentication failed'
});
}
next();
};
Use Javascript fetch API for sending JWT token as header authorization
fetch('backend_domain/dashboard', {
method: 'get',
headers: {
Authorization: JWT_Token
}
}).then(data => {..your operation here..})
Reference: fetch_mdn for better understanding of fetch API
I think the problem here is that you are getting an empty object in req.body when you try to pass it as a json string in postman. I would recommend either
pass your credentials in x-www-form-urlencoded tag in postman or
Using express.Router() and creating different files for routes
In your index.js file write:
app.use('/', require('./routes.js'))
And create a file with name routes.js and put your routes as this:
const express = require('express');
const router = express.Router();
router.post('/', (req, res) => {
let username = req.body.username;
let password = req.body.password;
console.log(req.body);
if (username !== process.env.USER_NAME && password !== process.env.USER_PASSWORD) {
res.json('Invalid credentials');
} else {
const token = jwt.sign({
username: username
}, process.env.SECRET_KEY, {
expiresIn: 3600
});
return res.send({token});
}
});
module.exports = router;
I am not exactly sure how to go about using/accessing the data requested from a discord oauth2 authentication. I have requested to access the guilds the user is in and the username and avatar of the user. I get a successful authentication, but my question is how do i use and access that data? This is my code currently:
server.js
const express = require('express');
const path = require('path');
const app = express();
app.use('/static', express.static(path.join(__dirname, 'static')));
app.get('/', (req, res) => {
res.status(200).sendFile(path.join(__dirname, 'index.html'));
});
app.listen(50451, () => {
console.info('Running on port 50451');
});
app.use('/api/discord', require('./api/discord'));
app.use((err, req, res, next) => {
switch (err.message) {
case 'NoCodeProvided':
return res.status(400).send({
status: 'ERROR',
error: err.message,
});
default:
return res.status(500).send({
status: 'ERROR',
error: err.message,
});
}
});
discord.js
const express = require('express');
const dotenv = require('dotenv').config()
const fetch = require('node-fetch');
const btoa = require('btoa');
const { catchAsync } = require('../utils');
const router = express.Router();
const scopes = ['identify', 'guilds'];
const CLIENT_ID = process.env.CLIENT_ID;
const CLIENT_SECRET = process.env.CLIENT_SECRET;
const redirect =
encodeURIComponent('http://localhost:50451/api/discord/callback');
router.get('/login', (req, res) => {
res.redirect(`https://discordapp.com/api/oauth2/authorize?client_id=${CLIENT_ID}&redirect_uri=${redirect}&response_type=code&scope=identify%20guilds`);
});
router.get('/callback', catchAsync(async (req, res) => {
if (!req.query.code) throw new Error('NoCodeProvided');
const code = req.query.code;
const creds = btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
const response = await fetch(`https://discordapp.com/api/oauth2/token?grant_type=authorization_code&code=${code}&redirect_uri=${redirect}`,
{
method: 'POST',
headers: {
Authorization: `Basic ${creds}`,
},
});
const json = await response.json();
res.redirect(`/success/?token=${json.access_token}`);
}));
module.exports = router;
Any help will be greatly appreciated. Thanks!
It's almost the same as the way you use the req.query.code to get the access_token.
const fetchDiscordUserInfo = await fetch('http://discordapp.com/api/users/#me', {
headers: {
Authorization: `Bearer ${json.access_token}`,
}
});
const userInfo = await fetchDiscordUserInfo.json();
yourUserId = `${userInfo.id}`;
yourUserName = `${userInfo.username}`;
// or simply...
console.log(userInfo);
I'm using express-jwt for athentication, and the following is my code:
api>routes/index.js:
var express = require('express');
var router = express.Router();
var jwt = require('express-jwt');
var auth = jwt({ secret: 'thisIsSecret', requestProperty: 'auth' });
after this inside index.js when i use auth middleware in
router.post('/locations/:locationId/reviews', auth, ctrlReviews.reviewsCreate);
route, when want to post reviews data with post-man, request goes to loading, and no response appear, but if remove auth from route request give response.
I have also checked with
var auth = jwt({
secret: process.env.JWT_SECRET,
userProperty: 'payload'
});
As mentioned in the comments, you're trying to handle valid and invalid tokens. This should be possible with something similar to the below code.
If you use Postman to call this with the following header, then you'll receive 200 OK, with a message of 'OK!'.
Authorization: Bearer validJWT
If you use Postman to call this without a valid JWT then you'll receive 401 Unauthorized with a message of 'invalid token...'.
var jsonwebtoken = require('jsonwebtoken');
var express = require('express');
var app = express();
var jwt = require('express-jwt');
var auth = jwt({ secret: 'thisIsSecret', requestProperty: 'auth'});
// Generate valid JWT
console.log(jsonwebtoken.sign({ foo: 'bar' }, 'thisIsSecret'));
app.post('/locations/:locationId/reviews', auth, function(req, res, next) {
// Log user details set in JWT
console.log(req.auth)
res.send('OK!');
});
// Handle invalid JWT
app.use(function(err, req, res, next) {
if (err.constructor.name === 'UnauthorizedError') {
res.status(401).send('invalid token...');
}
});
app.listen(3000, function() {
console.log('Server running on 3000')
})