You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
359 lines
12 KiB
359 lines
12 KiB
4 years ago
|
# discord-oauth2 [](https://www.npmjs.com/package/discord-oauth2)
|
||
|
|
||
|
A really simple to use module to use discord's OAuth2 API.
|
||
|
|
||
|
Please check out discord's OAuth2 documentation: https://discord.com/developers/docs/topics/oauth2
|
||
|
|
||
|
### Installing
|
||
|
|
||
|
```bash
|
||
|
npm install discord-oauth2
|
||
|
```
|
||
|
|
||
|
# Class constructor
|
||
|
|
||
|
One parameter is passed to the class constructor:
|
||
|
|
||
|
### `Options`
|
||
|
|
||
|
Since the module uses a modified version of [Eris](https://github.com/abalabahaha/eris) request handler, it takes the same options, all of them default to the default Eris Client options if no options are passed.
|
||
|
|
||
|
Request handler options:
|
||
|
```
|
||
|
requestTimeout: A number of milliseconds before requests are considered timed out.
|
||
|
|
||
|
latencyThreshold: The average request latency at which the RequestHandler will start emitting latency errors.
|
||
|
|
||
|
ratelimiterOffset: A number of milliseconds to offset the ratelimit timing calculations by.
|
||
|
|
||
|
```
|
||
|
|
||
|
Others, you can pass these options to the class constructor so you don't have to pass them each time you call a function:
|
||
|
```
|
||
|
version: The Discord API version to use. Defaults to "v7".
|
||
|
|
||
|
clientId: Your application's client id.
|
||
|
|
||
|
clientSecret: Your application's client secret.
|
||
|
|
||
|
redirectUri: Your URL redirect uri.
|
||
|
|
||
|
credentials: Base64 encoding of the UTF-8 encoded credentials string of your application, you can pass this in the constructor to not pass it every time you want to use the revokeToken() method.
|
||
|
```
|
||
|
|
||
|
# Events
|
||
|
|
||
|
In the Eris Library, client extends the `events` modules and the client is passed to the RequestHandler so it's able to emit events, this modified RequestHandler extends `events` so it can emit the same events.
|
||
|
|
||
|
There are only two events, `debug` and `warn`.
|
||
|
|
||
|
# Methods
|
||
|
|
||
|
### `tokenRequest()`
|
||
|
|
||
|
Only takes an object with the following properties:
|
||
|
|
||
|
`clientId`: Your application's client id. Can be omitted if provided on the client constructor.
|
||
|
|
||
|
`clientSecret`: Your application's client secret. Can be omitted if provided on the client constructor.
|
||
|
|
||
|
`scope`: The scopes requested in your authorization url, can be either a space-delimited string of scopes, or an array of strings containing scopes.
|
||
|
|
||
|
`redirectUri`: Your URL redirect uri. Can be omitted if provided on the client constructor.
|
||
|
|
||
|
`grantType`: The grant type to set for the request, either authorization_code or refresh_token.
|
||
|
|
||
|
`code`: The code from the querystring (grantType `authorization_code` only).
|
||
|
|
||
|
`refreshToken`: The user's refresh token (grantType `refresh_token` only).
|
||
|
|
||
|
|
||
|
Returns a promise which resolves in an object with the access token.
|
||
|
|
||
|
Please refer to discord's OAuth2 [documentation](https://discord.com/developers/docs/topics/oauth2#authorization-code-grant-access-token-exchange-example) for the parameters needed.
|
||
|
|
||
|
```js
|
||
|
const DiscordOauth2 = require("discord-oauth2");
|
||
|
const oauth = new DiscordOauth2();
|
||
|
|
||
|
oauth.tokenRequest({
|
||
|
clientId: "332269999912132097",
|
||
|
clientSecret: "937it3ow87i4ery69876wqire",
|
||
|
|
||
|
code: "query code",
|
||
|
scope: "identify guilds",
|
||
|
grantType: "authorization_code",
|
||
|
|
||
|
redirectUri: "http://localhost/callback",
|
||
|
}).then(console.log)
|
||
|
```
|
||
|
|
||
|
Using class constructor options, array of scopes and grantType refresh_token:
|
||
|
|
||
|
```js
|
||
|
const DiscordOauth2 = require("discord-oauth2");
|
||
|
const oauth = new DiscordOauth2({
|
||
|
clientId: "332269999912132097",
|
||
|
clientSecret: "937it3ow87i4ery69876wqire",
|
||
|
redirectUri: "http://localhost/callback",
|
||
|
});
|
||
|
|
||
|
oauth.tokenRequest({
|
||
|
// clientId, clientSecret and redirectUri are omitted, as they were already set on the class constructor
|
||
|
refreshToken: "D43f5y0ahjqew82jZ4NViEr2YafMKhue",
|
||
|
grantType: "refresh_token",
|
||
|
scope: ["identify", "guilds"],
|
||
|
});
|
||
|
|
||
|
// On successful request both requesting and refreshing an access token return the same object
|
||
|
/*
|
||
|
{
|
||
|
"access_token": "6qrZcUqja7812RVdnEKjpzOL4CvHBFG",
|
||
|
"token_type": "Bearer",
|
||
|
"expires_in": 604800,
|
||
|
"refresh_token": "D43f5y0ahjqew82jZ4NViEr2YafMKhue",
|
||
|
"scope": "identify guilds"
|
||
|
}
|
||
|
*/
|
||
|
```
|
||
|
|
||
|
### `revokeToken()`
|
||
|
|
||
|
Takes two parameters, the first one is the access_token from the user, the second is a Base64 encoding of the UTF-8 encoded credentials string of your application.
|
||
|
|
||
|
Returns a promise which resolves in an empty object if successful.
|
||
|
|
||
|
```js
|
||
|
const DiscordOauth2 = require("discord-oauth2");
|
||
|
const oauth = new DiscordOauth2();
|
||
|
|
||
|
const clientID = "332269999912132097";
|
||
|
const client_secret = "937it3ow87i4ery69876wqire";
|
||
|
const access_token = "6qrZcUqja7812RVdnEKjpzOL4CvHBFG";
|
||
|
|
||
|
// You must encode your client ID along with your client secret including the colon in between
|
||
|
const credentials = Buffer.from(`${clientID}:${client_secret}`).toString("base64"); // MzMyMjY5OTk5OTEyMTMyMDk3OjkzN2l0M293ODdpNGVyeTY5ODc2d3FpcmU=
|
||
|
|
||
|
oauth.revokeToken(access_token, credentials).then(console.log); // {}
|
||
|
```
|
||
|
|
||
|
### `getUser()`
|
||
|
|
||
|
Only takes one parameter which is the user's access token.
|
||
|
|
||
|
Returns the [user](https://discord.com/developers/docs/resources/user#user-object) object of the requester's account, this requires the `identify` scope, which will return the object without an email, and optionally the `email` scope, which returns the object with an email.
|
||
|
|
||
|
```js
|
||
|
const DiscordOauth2 = require("discord-oauth2");
|
||
|
const oauth = new DiscordOauth2();
|
||
|
|
||
|
const access_token = "6qrZcUqja7812RVdnEKjpzOL4CvHBFG";
|
||
|
|
||
|
oauth.getUser(access_token).then(console.log);
|
||
|
/*
|
||
|
{
|
||
|
username: '1337 Krew',
|
||
|
locale: 'en-US',
|
||
|
mfa_enabled: true,
|
||
|
flags: 128,
|
||
|
avatar: '8342729096ea3675442027381ff50dfe',
|
||
|
discriminator: '4421',
|
||
|
id: '80351110224678912'
|
||
|
}
|
||
|
*/
|
||
|
```
|
||
|
|
||
|
### `getUserGuilds()`
|
||
|
|
||
|
Only takes one parameter which is the user's access token.
|
||
|
|
||
|
Returns a list of partial [guild](https://discord.com/developers/docs/resources/guild#guild-object) objects the current user is a member of. Requires the `guilds` scope.
|
||
|
|
||
|
```js
|
||
|
const DiscordOauth2 = require("discord-oauth2");
|
||
|
const oauth = new DiscordOauth2();
|
||
|
|
||
|
const access_token = "6qrZcUqja7812RVdnEKjpzOL4CvHBFG";
|
||
|
|
||
|
oauth.getUserGuilds(access_token).then(console.log);
|
||
|
/*
|
||
|
{
|
||
|
"id": "80351110224678912",
|
||
|
"name": "1337 Krew",
|
||
|
"icon": "8342729096ea3675442027381ff50dfe",
|
||
|
"owner": true,
|
||
|
"permissions": 36953089,
|
||
|
"permissions_new": "36953089"
|
||
|
}
|
||
|
*/
|
||
|
```
|
||
|
|
||
|
### `getUserConnections()`
|
||
|
|
||
|
Only takes one parameter which is the user's access token.
|
||
|
|
||
|
Returns a list of [connection](https://discord.com/developers/docs/resources/user#connection-object) objects. Requires the `connections` OAuth2 scope.
|
||
|
|
||
|
```js
|
||
|
const DiscordOauth2 = require("discord-oauth2");
|
||
|
const oauth = new DiscordOauth2();
|
||
|
|
||
|
const access_token = "6qrZcUqja7812RVdnEKjpzOL4CvHBFG";
|
||
|
|
||
|
oauth.getUserConnections(access_token).then(console.log);
|
||
|
/*
|
||
|
[ { verified: true,
|
||
|
name: 'epicusername',
|
||
|
show_activity: true,
|
||
|
friend_sync: false,
|
||
|
type: 'twitch',
|
||
|
id: '31244565',
|
||
|
visibility: 1 } ]
|
||
|
*/
|
||
|
```
|
||
|
|
||
|
### `addMember()`
|
||
|
|
||
|
Force join a user to a guild (server).
|
||
|
|
||
|
Takes an object with the following properties:
|
||
|
|
||
|
`accessToken`: The user access token.
|
||
|
|
||
|
`botToken`: The token of the bot used to authenticate.
|
||
|
|
||
|
`guildId`: The ID of the guild to join.
|
||
|
|
||
|
`userId`: The ID of the user to be added to the guild.
|
||
|
|
||
|
Optional properties (the above ones are required):
|
||
|
|
||
|
`nickname`: Value to set users nickname to.
|
||
|
|
||
|
`roles`: Array of role ids the member is assigned.
|
||
|
|
||
|
`mute`: Whether the user is muted in voice channels.
|
||
|
|
||
|
`deaf`: Whether the user is deafened in voice channels.
|
||
|
|
||
|
Returns a member object if the user wasn't part of the guild, else, returns an empty string (length 0).
|
||
|
|
||
|
```js
|
||
|
const DiscordOauth2 = require("discord-oauth2");
|
||
|
const oauth = new DiscordOauth2();
|
||
|
|
||
|
oauth.addMember({
|
||
|
accessToken: "2qRZcUqUa9816RVnnEKRpzOL2CvHBgF",
|
||
|
botToken: "NDgyMjM4ODQzNDI1MjU5NTIz.XK93JQ.bnLsc71_DGum-Qnymb4T5F6kGY8",
|
||
|
guildId: "216488324594438692",
|
||
|
userId: "80351110224678912",
|
||
|
|
||
|
nickname: "george michael",
|
||
|
roles: ["624615851966070786"],
|
||
|
mute: true,
|
||
|
deaf: true,
|
||
|
}).then(console.log); // Member object or empty string
|
||
|
|
||
|
/*
|
||
|
{
|
||
|
nick: 'george michael',
|
||
|
user: {
|
||
|
username: 'some username',
|
||
|
discriminator: '0001',
|
||
|
id: '421610529323943943',
|
||
|
avatar: null
|
||
|
},
|
||
|
roles: [ '324615841966570766' ],
|
||
|
premium_since: null,
|
||
|
deaf: true,
|
||
|
mute: true,
|
||
|
joined_at: '2019-09-20T14:44:12.603123+00:00'
|
||
|
}
|
||
|
*/
|
||
|
```
|
||
|
|
||
|
### `generateAuthUrl`
|
||
|
|
||
|
Dynamically generate an OAuth2 URL.
|
||
|
|
||
|
Takes an object with the following properties:
|
||
|
|
||
|
`clientId`: Your application's client id. Can be omitted if provided on the client constructor.
|
||
|
|
||
|
`prompt`: Controls how existing authorizations are handled, either consent or none (for passthrough scopes authorization is always required).
|
||
|
|
||
|
`scope`: The scopes requested in your authorization url, can be either a space-delimited string of scopes, or an array of strings containing scopes.
|
||
|
|
||
|
`redirectUri`: Your URL redirect uri. Can be omitted if provided on the client constructor.
|
||
|
|
||
|
`responseType`: The response type, either code or token (token is for client-side web applications only). Defaults to code.
|
||
|
|
||
|
`state`: A unique cryptographically secure string (https://discord.com/developers/docs/topics/oauth2#state-and-security).
|
||
|
|
||
|
`permissions`: The permissions number for the bot invite (only with bot scope) (https://discord.com/developers/docs/topics/permissions).
|
||
|
|
||
|
`guildId`: The guild id to pre-fill the bot invite (only with bot scope).
|
||
|
|
||
|
`disableGuildSelect`: Disallows the user from changing the guild for the bot invite, either true or false (only with bot scope).
|
||
|
|
||
|
```js
|
||
|
const crypto = require('crypto')
|
||
|
const DiscordOauth2 = require("discord-oauth2");
|
||
|
const oauth = new DiscordOauth2({
|
||
|
clientId: "332269999912132097",
|
||
|
clientSecret: "937it3ow87i4ery69876wqire",
|
||
|
redirectUri: "http://localhost/callback",
|
||
|
});
|
||
|
|
||
|
const url = oauth.generateAuthUrl({
|
||
|
scope: ["identify", "guilds"],
|
||
|
state: crypto.randomBytes(16).toString("hex"), // Be aware that randomBytes is sync if no callback is provided
|
||
|
});
|
||
|
|
||
|
console.log(url);
|
||
|
// https://discord.com/api/oauth2/authorize?client_id=332269999912132097&redirect_uri=http%3A%2F%2Flocalhost%2Fcallback&response_type=code&scope=identify%20guilds&state=132054f372bfca771de3dfe54aaacece
|
||
|
|
||
|
```
|
||
|
|
||
|
# Debugging
|
||
|
|
||
|
By default when you log an error to the console, it will look something like this `DiscordHTTPError: 400 Bad Request on POST /api/v7/oauth2/token` followed by a very long stack trace what most of the times won't be useful (if you already know where the function is called).
|
||
|
|
||
|
To easily debug any issues you are having, you can access the following properties of the error object thrown:
|
||
|
|
||
|
`req`: The HTTP request sent to discord.
|
||
|
|
||
|
`res`: The HTTP response sent from discord to our request.
|
||
|
|
||
|
`code`: If the error is a `DiscordHTTPError`, it will be the HTTP status code of the response (same as `res.statusCode`).<br />
|
||
|
If the error is a `DiscordRESTError`, it will be a [Discord API JSON error code](https://discord.com/developers/docs/topics/opcodes-and-status-codes#json-json-error-codes).
|
||
|
|
||
|
`response`: An object containing properties that describe the error.<br />
|
||
|
If the error is a `DiscordHTTPError`, the object will have the `error` and `error_description` properties.<br />
|
||
|
If the error is a `DiscordRESTError`, the object will have the `message` and `code` (JSON error code. See `code`.) properties.
|
||
|
|
||
|
`message`: If the error is a `DiscordHTTPError`, it will be a string including the status of the HTTP request and the endpoint used.<br />
|
||
|
If the error is a `DiscordRESTError`, it will be a string including the error code and it's meaning.
|
||
|
|
||
|
`stack`: The error stack trace.
|
||
|
|
||
|
```js
|
||
|
// error.response for DiscordRESTError
|
||
|
{
|
||
|
message: 'Missing Permissions',
|
||
|
code: 50013
|
||
|
}
|
||
|
```
|
||
|
|
||
|
```js
|
||
|
// error.response for DiscordHTTPError
|
||
|
{
|
||
|
error: 'invalid_request',
|
||
|
error_description: 'Invalid "code" in request.'
|
||
|
}
|
||
|
```
|
||
|
|
||
|
# Contributing
|
||
|
|
||
|
All contributions are welcome.
|