David - Musings of an SRE

OAuth2 to Webhooks

I love how both Slack and Discord has a way to make use of the OAuth2 flow to directly retrieve webhooks urls that we can use to send out their messages.

This makes it really convenient to build integrations that would allow you to request for incoming webhooks on behalf of your users without having to take the extra step to process and retrieve incoming webhook links.

Discord

For example, in Discord, you can make a call to the following url (as an example) to get prompted to authorize the request for a webhook to a specific server and channel

https://discord.com/oauth2/authorize?response_type=code&client_id=<client_id>&scope=webhook.incoming&state=<state_nonce>&redirect_uri=<redirect_url>

Discord OAuth Screen

Once the request have been authorized, you’ll be returned the usual OAuth2 code that you can use to get an access/refresh token pair.

But because you’re using the webhook flow (see &scope=webhook.incoming in the above URL), you will get something extra with the access token which contains the webhook url that you can use to directly send a message to the channel and server that the user has filled in during the authorization flow.

{
  "token_type": "Bearer",
  "access_token": "GNaVzEtATqdh173tNHEXY9ZYAuhiYxvy",
  "scope": "webhook.incoming",
  "expires_in": 604800,
  "refresh_token": "PvPL7ELyMDc1836457XCDh1Y8jPbRm",
  "webhook": {
    "application_id": "310954232226357250",
    "name": "testwebhook",
    "url": "https://discord.com/api/webhooks/347114750880120863/kKDdjXa1g9tKNs0-_yOwLyALC9gydEWP6gr9sHabuK1vuofjhQDDnlOclJeRIvYK-pj_",
    "channel_id": "345626669224982402",
    "token": "kKDdjXa1g9tKNs0-_yOwLyALC9gydEWP6gr9sHabuK1vuofjhQDDnlOclJeRIvYK-pj_",
    "type": 1,
    "avatar": null,
    "guild_id": "290926792226357250",
    "id": "347114750880120863"
  }
}

(example above taken from the discord docs).

Slack

Similarly, in Slack, if you send an oauth2 authorize request with the &scope=incoming-webhook

https://slack.com/oauth/v2/authorize?scope=incoming-webhook,commands&client_id=<client_id>

Slack OAuth Screen

When the flow is completed, you’ll get the webhook details as part of the access token exchange.

{
    "ok": true,
    "access_token": "xoxp-XXXXXXXX-XXXXXXXX-XXXXX",
    "scope": "identify,bot,commands,incoming-webhook,chat:write:bot",
    "user_id": "XXXXXXXX",
    "team_name": "Your Workspace Name",
    "team_id": "XXXXXXXX",
    "incoming_webhook": {
        "channel": "#channel-it-will-post-to",
        "channel_id": "C05002EAE",
        "configuration_url": "https://workspacename.slack.com/services/BXXXXX",
        "url": "https://hooks.slack.com/TXXXXX/BXXXXX/XXXXXXXXXX"
    }
}

⚡Pretty convenient! ⚡

References