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.
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:
A
(let's call this account A/foo
)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.
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
.
The parameters used here are adapted from the "implicit" flow (RFC 6749 sections 4.2.1 and 4.2.2).
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:
response_type
- REQUIRED, value must be set to "token"
client_id
- REQUIRED, the client identifierwebhook_uri
- OPTIONAL, an endpoint to which responses (tokens or errors) should be postedscope
- OPTIONAL, the scope of the access request as described by RFC 6749 Section 3.3state
- RECOMMENDED, an opaque value used to maintain state between the request and the response, as described by RFC 6749 Section 4.2.1Clients 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.
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:
access_token
- REQUIRED, the access token issued by the auth servertoken_type
- REQUIRED, the token type as described in RFC 6749 Section 7.1 (e.g. "bearer"
)expires_in
- RECOMMENDED, token duration in seconds, as described in RFC 6749 Section 4.2.2scope
- OPTIONAL if identical to the scope requested by the client, otherwise REQUIRED.state
- REQUIRED if the state
parameter was present in the client authorization request. Must be the exact value received from the client.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.
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.
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:
redirect_uri
is replaced by webhook_uri
.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:
In the webhook flow, C
POSTs a request, with a set of parameters in the body. Some amount of time later (or maybe never), C
receives a POST request with a token (or error) in the body.
In the code flow, C
redirects the user's browser, with a set of parameters in the query. Some amount of time later (or maybe never), C
receives a GET request with an auth-code (or error) in the query. This auth-code is then exchanged for a token.
In the implicit flow, C
issues a redirect to the user, with a set of parameters in the query. Some amount of time later, C
receives a GET request. The token (or error) is in the fragment, which C
may or may not ever see.
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.)
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.