nicholastay / passport-discord

Passport strategy for authentication with Discord (discordapp.com)
ISC License
172 stars 55 forks source link

Failed to fetch user's guild #40

Open AshuInsideOut opened 3 years ago

AshuInsideOut commented 3 years ago

Is this occurring cause if rate limits or something?

seems to happen randomly.

image

c43721 commented 3 years ago

This happens when you hit the rate limit supposedly, but to reproduce:

1) Go to oauth login page 2) Double click on "Authorize" 3) Find error

I don't know what causes this, but I will try to look into it.

AshuInsideOut commented 3 years ago

Thanks....please do

Lusiny commented 3 years ago

I'm having the same problem if someone can tell me some way around the multiple clicks on the Authorize button.

Lusiny commented 3 years ago

After several hours thinking of various solutions to avoid this error I came to this code:

const express = require("express");
const app = express();

const passport = require("passport");
const DiscordStrategy = require("passport-discord").Strategy;

const Strategy = new DiscordStrategy({ 
    clientID: "", // your client id here
    clientSecret: "", // your client secret here
    callbackURL: "", // your callback url here 
    scope: ["guilds"] // your scopes here
}, async (accessToken, refreshToken, profile, cb) => {
    await process.nextTick(async () => {
        if (profile.guilds == undefined) return cb(null, false); // When there is an error fetching the user's guilds, the .guilds property returns undefined, so we must point out in the callback that all the information hasn't arrived with cb(null, false)

        return cb(null, profile);
    });
});

passport.use(Strategy);
passport.serializeUser((user, done) => {
    if (!user) return; // In serialization, if the value received is false, as we saw above, it means that the information did not arrive in its entirety, that is, it is a repeated request and therefore it did not get all the information, so we must return to avoid serialization errors
    return done(null, user);
});
passport.deserializeUser((obj, done) => done(null, obj));

app
// Put whatever you are using in your application
.use(passport.initialize())
.use(passport.session())
.get("/callback", function (req, res, next) { return passport.authenticate("discord", { failureRedirect: "/" }, async function (err, user, info) {
    if (err) {
        console.error(err); // In case of an error, it must always be registered the choice is yours
        return res.redirect('/');  // This part is very important, even if it gives an error, unless it is a 429 (rate limit), the client will have all the information requested from the user, so here you must put the url you want it to be sent to (you can use the req.session.backURL, for example)
    }

    await req.login(user, function (e) {
        if (e) return next(e); // As we are careful with user serialization here it will not return anything so this part is not really necessary
        return next();
    });
})(req, res, next); }, async function (req, res) {
    return res.redirect('/'); // Then we must redirect the user to wherever you want
})

IMPORTANT

c43721 commented 3 years ago

What we should do is see if this happens on any scope, or just the guilds scope.

I don't have time to look into this myself, but I know how to reproduce this, but I am unsure if this is a library bug or a Discord bug (and I'm leaning towards both).

Catdontpat commented 2 years ago

HEY! Sorry for the late response, if you're getting this error it's most likely caused by the actual `

Strategy.prototype.checkScope part, all you have to do is simply change the url in this._oauth2.get('https://discord.com/api/users/@me' + scope, accessToken, function(err, body, res)

to

this._oauth2.get('https://discord.com/api/users/@me/' + scope, accessToken, function(err, body, res)

What it's trying to do is do a function to pull the guilds from the api in the wrong way and putting guilds right next to @me rather than making a slash

Hopefully this should help ❤️