How to Use Discord Webhook With OAuth2 for Application Authorization
🔍 WiseChecker

How to Use Discord Webhook With OAuth2 for Application Authorization

Discord webhooks let you send automated messages to text channels without a full bot. OAuth2 is Discord’s standard for authorizing third-party applications to access user data. Combining both allows you to build a secure system where an external app sends notifications to a specific Discord channel only after a user grants permission via OAuth2. This article explains how to set up a Discord application, generate an OAuth2 authorization URL, and use the resulting access token to send webhook messages.

Key Takeaways: Discord Webhook + OAuth2 Authorization

  • Discord Developer Portal > Applications > OAuth2 > URL Generator: Create an authorization URL with the webhook.incoming scope to let users approve your app.
  • OAuth2 redirect URI: Your app receives a temporary code that must be exchanged for an access token using a POST request to Discord’s token endpoint.
  • Webhook URL in the access token response: The token response includes a webhook object containing the channel ID and the full webhook URL for sending messages.

ADVERTISEMENT

How Discord Webhook Authorization Works With OAuth2

Discord webhooks are simple HTTP endpoints that accept JSON payloads. Normally you create a webhook manually in a channel’s Integrations settings and copy its URL. That URL contains a unique ID and token that anyone can use to post messages without further authentication.

OAuth2 adds a layer of user consent. Instead of sharing a static webhook URL, your application requests permission from a Discord user to create a webhook on their behalf. The user clicks an authorization link, logs in, and approves the webhook.incoming scope. Discord then returns an access token that your app can use to create a webhook in a specific channel of the user’s choosing.

Prerequisites

Before you begin, you need a Discord application registered in the Developer Portal. You also need a web server or a serverless function that can handle HTTP requests and store tokens securely. The user who authorizes the application must have the Manage Webhooks permission in the target Discord server.

Steps to Authorize a Webhook Using OAuth2

This process has three phases: creating the authorization URL, exchanging the code for a token, and using the token to send a webhook message.

Phase 1: Generate the OAuth2 Authorization URL

  1. Open the Discord Developer Portal
    Go to https://discord.com/developers/applications and sign in with your Discord account.
  2. Select your application
    Click the application you want to use. If you have not created one, click New Application, give it a name, and confirm.
  3. Navigate to OAuth2 settings
    In the left sidebar, click OAuth2. Under the General tab, you see the Client ID and Client Secret. Copy the Client ID — you need it for the authorization URL.
  4. Add a redirect URI
    Scroll down to Redirects. Click Add Redirect and enter the URL where Discord sends the authorization code. For local testing, use http://localhost:3000/callback. Click Save Changes.
  5. Build the authorization URL
    Use the URL Generator at the top of the OAuth2 page. Select the webhook.incoming scope. Under Redirect URL, choose the redirect you just added. The generator shows a URL that looks like this:
    https://discord.com/api/oauth2/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI&response_type=code&scope=webhook.incoming
    Copy this URL. When a user visits it, Discord asks them to select a server and channel where the webhook will be created.

Phase 2: Exchange the Authorization Code for an Access Token

  1. Handle the redirect
    After the user approves the authorization, Discord redirects their browser to your redirect URI with a code query parameter. For example: http://localhost:3000/callback?code=abc123.
  2. Send a POST request to the token endpoint
    Your backend must exchange this code for an access token. Send a POST request to https://discord.com/api/oauth2/token with the following body parameters (use URL-encoded form data):
    client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&grant_type=authorization_code&code=abc123&redirect_uri=YOUR_REDIRECT_URI
  3. Parse the response
    Discord returns a JSON object containing access_token, token_type (always Bearer), expires_in, refresh_token, and a webhook object. The webhook object includes id, type, name, avatar, channel_id, and url. The url is the full webhook URL you will use to send messages.
  4. Store the token and webhook URL
    Save the access_token and the webhook.url in your database. The token expires after 7 days. Use the refresh_token to obtain a new token without asking the user to reauthorize.

Phase 3: Send a Webhook Message Using the Authorized Webhook

  1. Prepare the JSON payload
    Create a JSON object with a content field. For example:
    { "content": "Hello from your authorized webhook!" }
    You can also include embeds, username, and avatar_url fields.
  2. Send the POST request
    Use any HTTP client to send a POST request to the webhook URL you stored. The URL looks like:
    https://discord.com/api/webhooks/WEBHOOK_ID/WEBHOOK_TOKEN
    Set the Content-Type header to application/json. No additional authentication is needed because the webhook URL itself is the credential.
  3. Check the response
    If the request succeeds, Discord returns 204 No Content. If you receive a 400 Bad Request, check that your JSON is valid. A 404 means the webhook was deleted or the token is wrong.

ADVERTISEMENT

Common Mistakes and Limitations

Webhook Not Appearing in the Token Response

If the token response does not include a webhook object, the user did not complete the authorization flow correctly. The most common cause is that the user did not select a channel during the OAuth2 consent screen. Remind the user to choose a channel before clicking Authorize.

Access Token Expires Before You Send a Message

The access token expires after 7 days. Once you have the webhook URL, you do not need the access token to send messages. The webhook URL is permanent unless the webhook is deleted. Store the webhook URL immediately after the OAuth2 flow and use it directly.

User Cannot Select the Server or Channel

The user must have the Manage Webhooks permission in the server where they want to create the webhook. If the server dropdown is empty, the user lacks this permission in every server they own or manage. Ask the user to check their roles in the target server.

Bot Scope vs Webhook.incoming Scope

Do not confuse the bot scope with webhook.incoming. The bot scope adds a bot user to the server, which requires additional permissions and a bot token. The webhook.incoming scope only creates a webhook — no bot user is added. Use webhook.incoming when you only need to send messages programmatically.

OAuth2 Webhook Scope vs Bot Scope

Item webhook.incoming Scope bot Scope
What it creates A webhook URL for sending messages A bot user that joins the server
Permissions needed Manage Webhooks on the target channel Defined in the bot’s permission integer
Authentication method Webhook URL (ID + token) Bot token from the Developer Portal
Can read messages No Yes, with appropriate intents
Can edit/delete messages No Yes, if it sent them
User consent required Yes, via OAuth2 authorization Yes, via OAuth2 authorization
Best for Notifications, logs, simple message posting Interactive commands, moderation, complex logic

Use the webhook.incoming scope when your application only needs to send messages to a Discord channel and does not need to read or interact with users. Use the bot scope when you need a full interactive bot that can listen to events, respond to commands, and manage server resources.

The OAuth2 flow for a bot scope is identical to the webhook flow, except the scope value is bot and you must also specify the permissions parameter as a bitwise integer. The token returned is a bot token, not a webhook URL. You can combine both scopes in a single authorization request by separating them with a space, for example: scope=bot webhook.incoming.

You can now set up a Discord webhook authorized through OAuth2 for your application. The key steps are generating the correct authorization URL with the webhook.incoming scope, handling the callback to exchange the code for a token, and storing the webhook URL for future message sending. For production use, implement token refreshing with the refresh_token to avoid asking users to reauthorize every 7 days. You can also combine the webhook.incoming scope with other scopes like identify to access additional user information in the same OAuth2 flow.

ADVERTISEMENT