OAuth2 for webhooks

This is a proposal for a simple way to adapt the OAuth2 "implicit" flow for use with webhooks.

It is a fairly straightforward modification, but it creates a new flow in which the client can authenticate as its own user, server-to-server.

Goals

The limitations of normal flows

In the normal set of OAuth2 flows, the user's identity is owned/managed by the auth server A.

This means that if the user is currently using a different site (call it C), and they want C to perform some action on A, the user needs to:

  1. have an account with A (let's call this account A/foo)
  2. be present to instruct A to issue a token so that C can act on behalf of A/foo.

In some circumstances, the user may be mainly using site C (with account C/foo), and the requirement to both have/create an account on A and to be present to link them can be burdensome.

Improvement

Let's say the user has an existing account/identity with C (call it C/foo). The user would like to instruct C to interact with A (e.g. sending a message to A/bar), but without changing or linking identities.

Evidently, this cannot be done using the identity A/foo, because without the user's help, C has no knowledge of this identity or authorisation to act on its behalf. In fact, up to this point, the user might not have an account with A.

The goal of this proposed flow is to allow C to interact with A using the identity C/foo, without requiring the user to create or link an account on A. This is achieved by direct interaction between C and A.

Webhook Flow

The parameters used here are adapted from the "implicit" flow (RFC 6749 sections 4.2.1 and 4.2.2).

Access Request

The client sends a POST request to the auth server. It constructs the request body using the following parameters, encoded using the application/x-www-form-urlencoded format:

Clients MUST check the response code from the server, in addition to listening for error responses to the webhook.

A successful response from the auth server should be "201 Accepted", but clients must accept any 200-family response.

Access Token Response

The auth server sends a POST request to the client's webhook endpoint. It constructs the request body using the following parameters, encoded using the application/x-www-form-urlencoded format:

Immediate rejection

If the auth server can determine immediately that an access request will be rejected, it should respond to the access request with a 400-family code. The body is not specified.

For certain rejection reasons (for example, if the domain for webhook_uri is not on a whitelist), rejecting immediately may be more secure, to avoid initiating outgoing connections to unfamiliar domains.

Error Response

The auth server sends a POST request to the client's webhook endpoint. The request body must be application/x-www-form-urlencoded, with parameters identical to those from RFC 6749 Section 4.1.1.

Comparison with "implicit" and "code" flows

Differences to "implicit" flow

This flow is primarily based on the "implicit" flow, which defines most of this already: the "implicit" flow defines parameters, specifying their semantics, and that they should be encoded asapplication/x-www-form-urlencoded.

The only differences between these two flows are:

Synchronicity

Although it might initially seem like a webhook flow would contain more asynchronicity than the other flows, that is not the case. Let's compare some of the flows from the perspective of C only:

All of these flows are equally asynchronous, and equally simple. (The "code" flow has an extra step to exchange an auth-code for a token, but it's not a big difference.)

Summary

This is a simple modification, re-using standard messages (aside from the replacement of redirect_uri with webhook_uri). The primary change is using POST requests as the communication channel instead if passing those messages in the queries and fragments of a user redirect.

The end result is that a client can obtain access tokens from an auth server (and therefore perform actions on associated services) for users belonging to the client, not the auth server.