401 Unauthorized Request Discord API with OAuth - node.js

I'm wanting to allow users of my site that use Discord to be able to "automatically" join my guild.
I have everything done except I always get a 401: Unauthorized from Discord's API using the following;
router.get("/cb", passport.authenticate("discord", { failureRedirect: "/" }), async function(req, res) {
const data = { access_token: req.user.accessToken };
axios.put(`https://discordapp.com/api/v8/guilds/${config.CyberCDN.server_id}/members/${req.user.id}`, {
headers: {
"Content-Type": "application/json",
"Authorization": `Bot ${config.CyberCDN.bot_token}`
},
body: JSON.stringify(data)
}).then((success) => {
console.log(`[DASHBOARD] ${req.user.username}#${req.user.discriminator} - Logging in...`);
console.log(success.config.data)
console.log(success.response.status)
return res.status(200).redirect("/");
}).catch((error) => {
console.log(`[DASHBOARD] ${req.user.username}#${req.user.discriminator} - Failed Logging in...`);
console.log(error.config.data.replace(config.CyberCDN.bot_token,"TOKEN"))
console.log(error.response.status)
return res.status(403).redirect("/");
});
});
I don't understand how when everything I have done is correct;
I have even asked in the Discord-API server regarding this matter with the same issue,
I did however have it working ONE TIME and now it's broke again, I have 0 clue how it broke.
My scopes are as follow "oauth_scopes": ["guilds.join"]

I found a better solution to this problem I had:
const DiscordOauth2 = require("discord-oauth2");
const discord = new DiscordOauth2();
/**
* Other required stuff for express.js goes here...
*/
router.get("/login", passport.authenticate("discord"));
router.get("/cb", passport.authenticate("discord", { failureRedirect: "/forbidden" }), async function(req, res) {
req.session.user = req.user;
res.redirect('/');
});
router.get("/support", authOnly, async function(req, res) {
discord.addMember({
accessToken: req.session.user.accessToken,
botToken: config.CyberCDN.bot_token,
guildId: config.CyberCDN.server_id,
userId: req.session.user.id,
roles: [config.CyberCDN.site_role]
}).then((r) => {
if(r) {
let date = new Date(r.joined_at);
res.status(200).json({ status: "Joined Server" });
const embed = new Embed()
.title(`New User Joined Via Site\n${r.user.username}#${r.user.discriminator}`)
.colour(16763904)
.thumbnail(`https://cdn.discordapp.com/avatars/${r.user.id}/${r.user.avatar}.webp?size=128`)
.footer(`User joined at: ${date.toLocaleDateString()}`)
.timestamp();
dhooker.send(embed);
console.log(r)
}else{
res.status(401).json({ status: "Already In There?" });
}
});
});
Basically through browsing my initial 401: Unauthorized error stumbled across a nice little OAuth2 NPM For Discord called discord-oauth2 developed by reboxer and numerous other people, which can be found here.
The helpful part was documented further down the README.md of that repo, in relation to my problem. Relation found here
I have also contributed that they add the removeMember feature also.

Related

How can I implement passport with apple authentication

I have an iOS app and nodeJS backend. Currently I have implemented passport-facebook strategy. From the app I get the facebook token, and I send it to backend where I authorise the user.
// config
var FacebookTokenStrategy = require('passport-facebook-token');
const passport = require('passport')
const { facebook_client_id, facebook_client_secret } = require('../config')
passport.use(new FacebookTokenStrategy({
clientID: facebook_client_id,
clientSecret: facebook_client_secret,
}, function (accessToken, refreshToken, profile, done) {
done(null, profile)
}
));
And the middleware
const passport = require('passport')
require('../config/passport-facebook')
require('../config/passport-apple')
require('../config/passport')
const { INVALID_TOKEN, UNAUTHORIZED } = require('../config/constants')
module.exports = (req, res, next) => {
passport.authenticate(['apple','facebook-token', 'jwt'], function (err, user, info) {
if (err) {
if (err.oauthError) {
res
.status(400)
.json({ message: INVALID_TOKEN })
}
} else if (!user) {
res
.status(401)
.json({ message: UNAUTHORIZED })
} else {
req.user = user
next()
}
})(req, res, next);
}
Now I need to implement apple login. I tried using this library passport-apple
But I can not make it work. I am receiving the token from the app, send it to the back, but I only get
GET - /api/v1/shirts/?sorted%5BcreatedAt%5D=-1&filtered%5Bstate%5D=&pageNum=1&pageSize=10 - 302 - Found - 0b sent - 15 ms
I don't know if this is the correct approach. Should I get the user info from the app, send it to the backend and assign a JWT token to the created user? Or how can I do the same as I did with facebook?
After several try I find the solution thanks to this documentation https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens
You need to send that in your body POST:
{
"grant_type": "authorization_code",
"code": "YOUR_CODE",
}
code:
"The authorization code received in an authorization response sent to your app. The code is single-use only and valid for five minutes. This parameter is required for authorization code validation requests." Apple Documentation

Rendering Current Page With PhantomJS

I am building an analytics dashboard using the MERN stack (Express, Node) are the Important things to highlight.
As part of a dash view, I was trying to find if it's possible to trigger a PhantomJS call to create a pdf report using a button on the page itself.
Given you need to be logged in to see your own analytics, I can not just run phantom from the command line and pass it in the URL of one of the dashboard pages since it requires a login and queries to be made.
Is it possible to do this with phantomJS?
If I correctly understood your question.
Example:
[main.js]
const dashboardToPdfCtrl = require("./controllers/phantom/pdf");
router.route("/api/dashboard/phantom").post(dashboardToPdfCtrl.createPdf);
router.route("/api/dashboard/phantom/html")
.post(dashboardToPdfCtrl.createDashboard);
When the user clicks on the "button" you can validate the USER according to the architecture of your application.
[pdf.js]
exports.createPdf= async (req, res) => {
if (!req.user || !req.user.sub) {
return res
.status(401)
.send({ message: 'No authorization token was found' });
}
const instance = await phantom.create();
const page = await instance.createPage();
const settings = {
operation: "POST",
encoding: "utf8",
headers: {
"Content-Type": "application/json"
},
data: JSON.stringify({
user: req.body.userId,
anyDataYouNeedToRender: req.body.anyDataYouNeedToRender
})
};
//POST request to /api/dashboard/phantom/html
await page.open(
`${process.env.HOST}:${
process.env.PORT
}/api/dashboard/phantom/html`,
settings
);
//Save the content of /public/dashboard/dashboard.html with received data to pdf
const pageSaved = await page.render(
path.resolve(`./public/dashboard/file.pdf`)
);
if (pageSaved) await instance.exit();
}
exports.createDashboard = (req, res) => {
res.render(
path.resolve("./public/dashboard/dashboard.html"),
{ user: req.body.user,
anyDataYouNeedToRender: req.body:anyDataYouNeedToRender
}
);
};
Is that what you were looking for? I want to help you, feel free to ask detalization.
P.S. As friends told before in comments, it will be great if you give us more information to understend you goal.

How to make subsequent requests using mwbot requesting Mediawiki

I got this error when I make subsequent request using mwbot on node.
response:
{ login:
{ result: 'Aborted',
reason: 'Cannot log in when using MediaWiki\\Session\\BotPasswordSessionProvider sessions' } } }
I am reading pages from mediawiki by providing a title. I thought that every request would need to login to read, but it seemed that I was wrong because this error seemed to complain that I already have logged in. But I don't know how the session can be read or how to find out that I already logged in or not.
the route:
router.get('/wikipage/:title', function(req, res, next) {
let title = req.params.title;
const MWBot = require('mwbot');
const wikiHost = "https://wiki.domain.com";
let bot = new MWBot();
let pageContent = "wiki page not created yet, please create";
bot.login({
apiUrl: wikiHost + "/api.php",
username: "xxx#apiuser",
password: "xxxxx"
}).then((response) => {
console.log("logged in");
return bot.read(title);
}).then((response) => {
for(let prop in response.query.pages) {
pageContent = response.query.pages[prop]['revisions'][0]['*'];
console.log("pageContent:", pageContent);
break;
}
res.json({
data: pageContent
});
}).catch((err) => {
// Could not login
console.log("error", err);
});
});
module.exports = router;
I presume you are running this in a browser, in which case the browser takes care of session cookie handling. You can check it the usual way via document.cookie.

Mean.js req.isAuthenticated is showing fail?

i have downloaded meanjs version#0.1.12.here i have used two servers for front end i hvae used angular with ionic its running in localhost:3000,for backend i have used meanjs.in that meanjs i have created signup,signin and articles.when ever i am using meansjs as a backend and front end it's working fine .but when i connect to another server(localhost:3000) signup and signin working fine but when ever i am creating articles i am getting 401 unauthorized bcoz of that req.isAuthenticated() function.when ever i create article module req.isAuthenticated() getting fail.req.isAuthenticated() i dono what should i pass for this function i have included my code anyone help me out
now i am passing data like this
$http.post('http://192.168.1.14:3000/articles', credentials).success(function(response,data,errorResponse) {
// If successful we assign the response to the global user model
//$scope.authentication.user =response;
console.log(response);
console.log(data);
// And redirect to the index page
$location.path('/tab/account');
}, function(response,data,errorResponse) {
$scope.error = errorResponse.data.message;
console.log($scope.error);
console.log(data);
});
routes:
app.route('/articles')
.get(users.requiresLogin,articles.list)
.post(users.requiresLogin,articles.create);
login checkup
/**
* Require login routing middleware
*/
exports.requiresLogin = function(req, res, next) {
//console.log(req.isAuthenticated());
console.log(req);
if (!req.isAuthenticated()) {
return res.status(401).send({
message: 'User is not logged in'
});
}
next();
};
/**
* User authorizations routing middleware
*/
exports.hasAuthorization = function(roles) {
var _this = this;
console.log('sss');
return function(req, res, next) {
_this.requiresLogin(req, res, function() {
if (_.intersection(req.user.roles, roles).length) {
return next();
} else {
return res.status(403).send({
message: 'User is not authorized'
});
}
});
};
};
I think I had the same problem. Make sure to check your policies folder on the server side.
roles: ['user'],
allows: [{
resources: '/articles',
permissions: ['get', 'post']
}, {
resources: '/articles/:articlesId',
permissions: ['get']
}, {
resources: '/articles',
permissions: ['post']
}]
Add the resource path /articles and permissions.

sails session writing bug

I'm using sails 0.10.4 and stumbled with one pretty annoying bug. When user logs in I write his data into the req.session.user then in policies I can retrieve his data such as his role, password etc. But the req.session.user becomes undefined when I go out of the login action. Do you have any ideas how to handle this? Here's the code:
api/controllers/User.js :
module.exports = {
login: function (req, res) {
Users.findOneByEmail(req.param('email'))
.exec(function (err, user) {
if ((err) || (!user)) {
res.send({
error: 'User not found'
});
return;
}
if (!passwordHash.verify(req.param('password'), user.password)) {
res.send({
error: 'Incorrect passwpord'
});
return;
}
req.session.user = user;//I write user into the session
res.send({
user: user
});
});
}
}
api/policies/isLoggedIn.js
module.exports = function (req, res, next) {
if (req.headers.authentication) {
var credentials = JSON.parse(req.headers.authentication);
if(req.session.user.login === credentials.login)//User doesn't exist in session
return next();
}
}
In a testing environment , this issue can happen when testing with Supertest and not defining an agent
var agent = request.agent(app);
agent.post('/api/login',{email:'foo#bar.com',password:'foobar})
.end(function(err,res){...; done();});
It is the correct way to work with sessions, simply using request.post would not work as it would reinit the session variable as soon as the response is sent, even if we are chaining requests inside the same test.
Learnt it the hard way, so I hope it can help some lost developper.

Resources