Unlocking Discord Account Information through OAuth2

Currently, I am in the process of developing a moderation bot for Discord. I am working on implementing a paid plan and as part of that, I require users to log in with their Discord account using OAuth2. This allows me to retrieve user data and identify which server has subscribed to the paid plan. To facilitate this, I have created an OAuth2 URL and configured a redirect to

After a user logs in, they will be directed to this URL: . At this point, my goal is to retrieve user data such as profile picture and username. How can I achieve this?

Answer №1

If you're diving into Oauth2, this answer will steer you in the right direction. I'll be showcasing JS examples utilizing the node-fetch library for making web requests, assuming you have an express backend set up.

First off, you need to guide the user to authorize their account with your client ID and the identify scope. On authorization, they will be redirected to your designated redirect URI (https://example.com/redirect as an example).

Upon redirection, a code GET parameter will be present in the URL they land on. Grab this code and dispatch it to Discord's token URL to obtain an access token:

app.get('/redirect', async function (req, res) {
    // Retrieve the code from GET params
    var code = req.query.code;
    
    // Create the POST body
    var body = {
        'client_id': CLIENT_ID,
        'client_secret': CLIENT_SECRET,
        'grant_type': 'authorization_code',
        'code': code,
        'redirect_uri': 'https://example.com/redirect',
    };

    // Send POST request to Discord
    var site = await fetch("https://discord.com/api/v9/oauth2/token", {
        method: 'POST',
        body: JSON.stringify(body),
        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    });

    // Parse the response
    var response = await site.json();
    var accessToken = response['access_token'];
    res.send(`Access token: ${accessToken}`);
})

Using the accessed token provided by Discord's response, you can proceed with a GET request to fetch information about the current user, employing an Authorization header of Bearer XXXXX (substitute XXXXX with your access token):

var site = await fetch("https://discord.com/api/v9/users/@me", {
    method: 'GET',
    headers: {'Authorization': `Bearer ${accessToken}`}
});
var response = await site.json();
var username = response.username;

Given that I'm unaware of the specific libraries you're integrating, this should give you a solid foundation and understanding of the steps required to attain the desired information.

Answer №2

I have a file that may interest you.

import { CLIENT_ID, CLINET_SECRET, AUTHORIZATION_URL, REDIRECT_URL } from '../config/keys';
import React, { useEffect } from 'react';
import axios from 'axios';

const Authentication = (props) => {
    const getUserGuilds = async (accessToken) => {
        // console.log(`Guild ${accessToken.data.token_type} ${accessToken.data.access_token}`);
        try {
            const response = await axios.get('https://discord.com/api/users/@me/guilds', {
                headers: {
                    authorization: `${accessToken.data.token_type} ${accessToken.data.access_token}`
                }
            });
            // console.log(response.data);
            return response.data;
        } catch (error) {
            console.log(error);
        }
    }
    const getUserInfo = async (accessToken) => {
        // console.log(accessToken);
        // console.log(`User ${accessToken.data.token_type} ${accessToken.data.access_token}`);
        try {
            const response = await axios.get('https://discord.com/api/users/@me', {
                headers: {
                    authorization: `${accessToken.data.token_type} ${accessToken.data.access_token}`
                }
            });
            // console.log(response.data);
            return response.data;
        } catch (error) {
            console.log(error);
        }
    }
    const getToken = async (code) => {
        try {
            const options = new URLSearchParams({
                client_id: CLIENT_ID,
                client_secret: CLINET_SECRET,
                code,
                grant_type: 'authorization_code',
                redirect_uri: REDIRECT_URL,
                scope: 'identify guilds',
            });
            const result = await axios.post('https://discord.com/api/oauth2/token', options);
            return result;
        } catch (error) {
            console.log(error);
        }
    }

    const getInfo = async (code) => {
        const accessToken = await getToken(code);
        const userInfo = await getUserInfo(accessToken);
        const guildInfo = await getUserGuilds(accessToken);
        console.log({ userInfo, guildInfo });
    }

    useEffect(() => {

        const urlSearchParams = new URLSearchParams(window.location.search);
        const params = Object.fromEntries(urlSearchParams.entries());
        // console.log(params);
        if (!params.code) return;
        getInfo(params.code);
    });
    return (
        <div className="Authentication">
            <br />
            <a className="btn" href={AUTHORIZATION_URL} >Sign in with discord</a>
        </div>
    )
}

export default Authentication;

Answer №3

My current understanding is that I am interested in creating a login system, and you are suggesting using Discord for this purpose. Here is a helpful resource you can reference: https://www.youtube.com/watch?v=tSS8VKwwjp0

Answer №4

Apologies for the delay, here is the modified version:

  done(null, user);
  });
  passport.deserializeUser((obj, done) => {
  done(null, obj);
  });
  
  passport.use(new Strategy({
    clientID: "YOUR_CLIENT_ID",
    clientSecret: "YOUR_SECRET_KEY",
    callbackURL: "http://localhost:8000/callback",
    scope: [ "identify", "guilds" ],
  },
  (accessToken, refreshToken, profile, done) => {
  process.nextTick(() => done(null, profile));
  }));
  
  app.use(session({
  secret: '123',
  resave: false,
  saveUninitialized: false,
  }));
  
  app.use(passport.initialize());
  app.use(passport.session());
  app.use(helmet());
  
  app.locals.domain = process.env.PROJECT_DOMAIN;


app.engine('.ejs', ejs.__express);
app.set('views',__dirname+'/views');
app.use(express.static("public"));

var bodyParser = require("body-parser");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ 
extended: true
})); 

function checkAuth(req, res, next) {
if (req.isAuthenticated()) return next();
req.session.backURL = req.url;
res.redirect("/login");
}

const renderTemplate = (res, req, template, data = {}) => {
const baseData = {
bot: client,
path: req.path,
user: req.isAuthenticated() ? req.user : null
};
res.render(path.resolve(`${templateDir}${path.sep}${template}`), Object.assign(baseData, data));
};

app.get("/login", (req, res, next) => {
if (req.session.backURL) {
req.session.backURL = req.session.backURL;
} else if (req.headers.referer) {
const parsed = url.parse(req.headers.referer);
if (parsed.hostname === app.locals.domain) {
req.session.backURL = parsed.path;
}
} else {
req.session.backURL = "/";
}
next();
},
passport.authenticate("discord"));

app.get("/connection-error", (req, res) => {
renderTemplate(res, req, "autherror.ejs");
});

app.get("/callback", passport.authenticate("discord", { failureRedirect: "/autherror" }), async (req, res) => {
if (req.session.backURL) {
const url = req.session.backURL;
req.session.backURL = null;
res.redirect(url);
} else {
res.redirect("/");
}
});

app.get("/logout", function(req, res) {
req.session.destroy(() => {
req.logout();
res.redirect("/");
});
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Enhancing HTML with VueJS and managing imports

After successfully developing a Single Page Application using VueJS, I realized that the SEO performance was not up to par. To combat this, I decided to create a standard HTML website with some pages incorporating VueJS code (since my hosting environment d ...

Enhancing User Experience with Load Indicator during State Changes in React Native

I'm facing an issue where the page for displaying a single item is loading slowly - I need to delay the page from loading until the object has changed. After checking the navigation params through console log, I can see that the id changes when each b ...

What is the best way to utilize the data being returned from PHP in JQuery or JavaScript?

There's an AJAX request hitting a php file to fetch some data, which looks like this: 21-12-12:::visits;45;;pageviews;344---22-10-10:::visits;71;;pageviews;34---15-01-11:::visits;4;;pageviews;30 Do you see the pattern? It resembles a multidimensiona ...

Converting JSON List to String List in a Spring MVC Controller

I am trying to pass the following List example: {"id":[1]} To this controller: public String addUsersToProject(@RequestBody List<String> usersIds, @PathVariable String projectTitle){..} However, I am encountering an issue where the list cannot be ...

Leverage JavaScript to update the name of a Google Spreadsheet using the latest data

Here is some code that allows you to rename a document: function renameFile() { var s = SpreadsheetApp.getActiveSpreadsheet(); s.rename("new file name"); } Can you modify this function to rename the file to "new filename 1/18"? Remember, where 18 r ...

In Python, extract data from the top level of a JSON file

Looking for assistance with parsing a JSON stored as a string: message = """{"info":{"keyVersion":1,"timestamp":"2020-11-05 20:00:00","encryptedData":"75657374696f6e732068617665207265636 ...

Rails - implementing ajax in partials causing an error: 'cannot find method render'

I am encountering an issue with my form partial located within a div that has the id "chapcomments". The form includes a submit button: <%= f.submit "Post", remote: true %> Within the correct view folder, I have a file named create.js.erb which con ...

What is the process for transferring ng-model values to a table in Angular?

My goal is to populate a table with JSON data using ng-repeat by clicking a button. I need to input either a first name or last name in order to display the results in the table. Is this the correct JavaScript function for achieving this? JavaScript Funct ...

Using the v-for directive in Vue.js to loop through an array and display

Looking at the image provided, I am trying to access the content. I attempted to do so using element.comments.content, but it did not seem to work as expected. Here is the snippet of code: <div class="fil-actualites-container"> <div cl ...

Is the Sina Weibo API PHP demo malfunctioning?

I've been attempting to authenticate with oAuth2 using Sina Weibo's API, but have been unsuccessful so far. I found the demo for the V2 of the SDK at http://code.google.com/p/libweibo/ However, when I run it, all I see is: array 'oauth_t ...

Commit to persevering until you achieve success

I'm currently working with native node.js Promises and did not find any useful information in this thread. Essentially, I am dealing with a function that looks like this: var foo = foo (resolve, reject) { return obj .doA() .doB() ...

Extracting information from a JSON response in Swift

[{ "_text" = "turn off the air con"; confidence = "0.609"; entities = { "on_off" = ( { value = off; } ); }; intent = "aircond_temperature"; }] In a JSON response named "outcomes ...

Tips for submitting a jQuery star rating:

I recently installed and added a plugin to one of my pages that transforms radio buttons into stars. While the form control works perfectly, I am facing an issue with submitting the form. The radio buttons are grouped together as stars but they do not subm ...

Obtain asynchronous view model for component

Is it possible to retrieve a view model from the server and incorporate it into my component? I attempted to do so with the following code snippet, but it is not working as expected: function fetchViewModelFromServerAsync(){ setTimeout(function(){ ...

The object is given a value in the form of a string, even though it is a strongly-typed variable

I'm encountering something unusual in my code. In the following example, there is a (change) event that captures the current value selected by the user from a dropdown menu. <div style="padding-right: 0; width: 100%;"> <label st ...

A guide to sending props to a CSS class in Vue 3

I need to develop a custom toast component that includes a personalized message and class. While I have successfully passed the message as props, I am encountering difficulties in applying the bootstrap class. Component File: Toast.vue <script ...

Close overlay panel in PrimeFaces calendar

One of the components I’m currently working with is an overlayPanel that contains a calendar. Here's a snippet of the code: <p:overlayPanel hideEffect="fade" showCloseIcon="true" dismissable="true" > <h:form> <p:p ...

Is the Android/JSON response indicating a false value?

I am currently in the process of developing an Android App that connects to a MySQL database on Hosting24.com via PHPMyAdmin. The main purpose of this app is to allow users to sign up by entering their details into an EditText box, which will then be store ...

Google-play-scraper encounters an unhandled promise rejection

I'm trying to use the google-play-scraper library with Node.js, but I keep encountering an error when passing a variable as the 'appId'. How can I resolve this issue? Example that works: var gplay = require('google-play-scraper') ...

Is there a way to compare two regex values using vuelidate?

Can someone assist me with validating an input field using vuelidate? I am looking to return a valid result if either of the two regular expressions provided below is true. const val1 = helpers.regex('val1', /^\D*7(\D*\d){12}\ ...