Skip to content

Latest commit

 

History

History
266 lines (174 loc) · 14.4 KB

AutoAuth.md

File metadata and controls

266 lines (174 loc) · 14.4 KB

AutoAuth

AutoAuth (working title) is an extension to IndieAuth to allow clients to obtain tokens for other sites without the user being present to complete an interactive flow. Obtaining those tokens is controlled by the user's authorization endpoint, which allows the user to still be in control of tokens generated for the client.

[TOC]

Participants

  • User: the end user.
  • Authorization Endpoint: Authorization Endpoint on the user's URL.
  • Resource: protected resource requiring a token connected to the user to access
  • Token Endpoint: Unless otherwise specified, the Token Endpoint of the Resource. Verifies and grants requests for tokens.
  • Client: Application the user is authorizing to request tokens in their name.

Detecting Authorization Requirements of a Resource

The possibility to access a resource through AutoAuth is discovered through the WWW-Authenticate header field, as described in RFC6750. In addition to this, a Link header with a rel value of token_endpoint has to be present.

If the resource contains information for non-authorized requests, it MUST return a non-error HTTP code (commonly 200) to requests not containing a token. An example of this would be a feed of posts that also contains public posts accessible to anyone. The presence of the WWW-Authenticate header indicates to the client that private posts with a limited audience might be available to it after authorization. If no access at all is granted without authorization, it SHOULD return code 401 Unauthorized.

GET https://example.org/resource
HTTP/1.1 200 OK
WWW-Authenticate: Bearer realm="posts" scope="read"
Link: <https://example.org/token>; rel="token_endpoint"

(NOTE: both the realm and scope attributes in the example above are OPTIONAL)

If the client does not already possess an applicable token, it can use AutoAuth to have the user's authorization endpoint obtain one for it. HTTP defines the concept of "protection spaces" for which authorization credentials are valid:

A protection space is defined by the canonical root URI (the scheme and authority components of the effective request URI [...]) of the server being accessed, in combination with the realm value if present.

General Notes about Requests

Following OAuth 2.0, all exchanges unless noted otherwise happen through POST requests with form-encoded payloads and JSON response types. Applications SHOULD use the appropriate Content-Type and Accept headers to indicate this.

Obtaining an Access Token for the Resource

The guardian of the user's identity in IndieAuth is the authorization endpoint. It is tasked here with obtaining tokens for the resource. The owner of the resource will need a confirmation that request is made at the behest of the user, and the authorization endpoint is able to provide this very similarly to how it confirms the identity in IndieAuth.

Token Request

The authorization endpoint creates an unique authorization code. With this code, a POST request to the resource's token endpoint is made. This is similar to the authorization flow in in IndieAuth, except that the authorization and token endpoints here belong to different sites. This request contains the following parameters:

  • grant_type=authorization_code
  • code - The authorization code generated by the authorization endpoint. See https://tools.ietf.org/html/rfc6749#section-4.1.2 for requirements on the authorization code.
  • root_uri- The root URI of the protection space
  • realm - the realm requested if any
  • scope - the scope requested (note that the auth endpoint could decide here to not request a scope the client asked for)
  • state - a randomly chosen spoofing-protection parameter which will be included in the callback. If working with client requests as described below, the authorization endpoint MUST NOT reuse the state used by the client.
  • callback_url - URL owned by the authorization endpoint to send the token to after the authorization code has been verified
  • me - the users URL
  • client_id - URL of the authorization endpoint
POST https://example.org/token
Content-Type: x-www-form-urlencoded
Accept: application/json

grant_type=authorization_code
&code=xxxxxxxxx
&root_uri=https://example.org
&realm=posts
&scope=read
&state=4234067
&callback_url=https://user.example/auth?x=callback
&me=https://user.example/
&client_id=https//user.example/auth

Response

If the token endpoint agrees to proceed with the process, the token endpoint returns a HTTP 202 Accepted response. Otherwise, it returns an OAuth 2.0 error.

The token endpoint can choose to continue the process synchronously, so the authorization code verification and even the callback can happen before this request returns.

Note that this request is not yet verified to actually be from the user's authorization endpoint, so aborting here should only happen in cases where no sensitive information is revealed. E.g. it is safe to return an error if the protection space is unknown or never granted access to, but user-specific decisions could reveal sensitive information and thus should not be made here.

Authorization Code Verification Request

The token endpoint needs to verify that the authorization code is valid and that it was issued for the matching parameters. For this, it discovers the authorization endpoint from the user's page (me). Discovery works like in IndieAuth, except that the me value can not change: Permanent redirects (301, 308) are NOT allowed. It then checks that the URL found for the authorization endpoint is equal to client_id. If it is equal, it sends it a verification request containing the code, me, root_uri, realm (if one was requested), scope and callback_url parameters.

POST https://user.example/auth
Content-Type: x-www-form-urlencoded
Accept: application/json

code=xxxxxxxxx
&root_uri=https://example.org
&realm=posts
&scope=read
&callback_url=https://user.example/auth?x=callback
&me=https://user.example/

The authorization endpoint will validate that the code corresponds with the given parameters (including the value or absence(!) of realm). If it does, a HTTP 200 response is returned, otherwise an OAuth 2.0 error response.

Access Token Callback

If the verification was successful, the token endpoint can now assume the request is genuine.

If it is willing to grant the token as requested, it generates a token and sends it to the Callback URL using a POST request. Its parameters are:

  • access_token - the token
  • token_type: Bearer
  • state - the state as submitted by the authorization endpoint in the token request
  • scope - the scopes for which the token was granted (space-separated list). OPTIONAL if equal to the requested scopes.
  • expires_in - time in seconds in which the token expires. RECOMMENDED

If it is not willing to grant the token, it sends an OAuth 2.0 error message to the Callback URL instead, also adding the state parameter.

Accessing the Protected Resource

The token can now be used to request the resource. It is included in an Authorization header with the Bearer HTTP authorization scheme.

Allowing External Clients to obtain Tokens

The above describes how a token can be obtained, but does not prescribe how applications requiring tokens can communicate with the authorization endpoint to trigger this flow. This section adds these pieces to allow applications that are not tightly integrated with the authorization endpoint to obtain tokens through a standardized and safe mechanism. Since all tokens pass through the authorization endpoint, it can keep a record of them and the user can always use them to request revocation at the resource, without the client application cooperating.

Granting Token-Request Permission to the Client

The Client application can obtain a token authorizing it to make requests for tokens for external resources through an IndieAuth authorization flow. It requests scopes prefixed with request_external_token, i.e. to obtain permission to request tokens with read scope, it requires a scope of request_external_token:read.

Callback-based Flow

External Token Request

When the client wants to request a token for a resource, it sends a request to the Authorization Endpoint to obtain one. The client makes a POST request to the authorization endpoint with an authorization header containing its token and the following parameters:

  • response_type=external_token
  • target_url- the URL of the resource for which to obtain the token
  • state - a randomly chosen spoofing-protection parameter which will be included in the callback
  • scope - A space-separated list of scopes the client is requesting, e.g. "read". The client must be authorized to request each of the scopes, by having a matching request_external_token: scope itself.
  • callback_url- the URL on which the client wants to receive the token
POST https://user.example/auth
Authorization: Bearer CLIENT_TOKEN
Content-Type: application/x-www-form-urlencoded
Accept: application/json

response_type=external_token
&target_url=https://example.org/resource
&state=1234567890
&scope=read
&callback_url=https://client.example/callbacks
Response

If the authorization endpoint accepts the request by the client, it returns a HTTP 202 Accepted response. Otherwise, it returns an OAuth 2.0 error.

Obtaining the Token

The authorization endpoint now goes through the flow as described above and obtains a token. If it receives an error at any step, it POSTs it to the callback_url, with the state parameter added.

External Token Callback

If the token was successfully obtained, the callback to the client contains the same information as the Access Token Callback, but with the state parameter value submitted by the client in the External Token Request, and the realm the token is for added.

The client can now use the token to make queries.

Polling-based Flow

Alternatively, the client can poll for information. This is especially relevant if the client is a client-side application on the user's device that is not able to provide a publicly available callback URL.

The polling mechanism in this flow is closely based on the OAuth2 Device Flow.

External Token Request

(Identical to callback flow, except there is no callback URL and no state)

When the client wants to request a token for a resource, it sends a request to the Authorization Endpoint to obtain one. The client makes a POST request to the authorization endpoint with an authorization header containing its token and the following parameters:

  • response_type=external_token
  • target_url- the URL of the resource for which to obtain the token
  • scope - A space-separated list of scopes the client is requesting, e.g. "read". The client must be authorized to request each of the scopes, by having a matching request_token scope itself.
POST https://user.example/auth
Authorization: Bearer CLIENT_TOKEN
Content-Type: application/x-www-form-urlencoded
Accept: application/json

response_type=external_token
&target_url=https://example.org/resource
&state=1234567890
&scope=read
Response

If the authorization endpoint accepts the request by the client, it returns a HTTP 200 OK response containing

  • request_id- a randomly chosen unique ID by which the server can match later polling to the request. Note that this takes the security role of state and has to be private and unguessable.

  • interval - OPTIONAL polling interval in seconds.

    HTTP/1.1 200 OK
    Content-Type: application/json
    
    {
        "request_id": "abcdefg",
        "interval": 5
    }

Otherwise, it returns an OAuth 2.0 error.

Obtaining the Token

The authorization endpoint now obtains the token as above. Once the process is complete, it provides the client with the details when it polls the next time.

Polling

The client regularly polls the authorization endpoint with requests including its token and the following parameters:

  • request_id- the request id it got assigned in the response to the External Token Request

If the access token is available, the authorization endpoint returns the information to the client. It includes the data it received through the the Access Token Callback, excluding the state and adding the realm. If it is not available, the responses are the same as in the OAuth2 Device Flow: https://tools.ietf.org/html/draft-ietf-oauth-device-flow-14#section-3.5

Most notably, the new error codes are:

   authorization_pending
      The authorization request is still pending as the end user hasn't
      yet completed the user interaction steps (Section 3.3).  The
      client SHOULD repeat the Access Token Request to the token
      endpoint (a process known as polling).  Before each new request
      the client MUST wait at least the number of seconds specified by
      the "interval" parameter of the Device Authorization Response (see
      Section 3.2), or 5 seconds if none was provided, and respect any
      increase in the polling interval required by the "slow_down"
      error.

   slow_down
      A variant of "authorization_pending", the authorization request is
      still pending and polling should continue, but the interval MUST
      be increased by 5 seconds for this and all subsequent requests.

   access_denied
      The end user denied the authorization request.

Privacy Considerations

To allow the user to restrict future access of the client, token endpoints MUST support token revocation. Authorization endpoints MUST keep records of tokens issued, and allow the user to revoke them. Systems that integrate the User's Token and Authorization endpoints SHOULD automatically revoke tokens that have been obtained with the Client's credentials if the Client's token is revoked (either by the user, or through Token Revocation)

Authorization endpoints are encouraged to allow further restrictions of the power of a granted token, e.g. to specific domains.

Fetching a file with authorization for the user clearly links the request to the user. Clients should not make such requests unexpectedly, even when they have been granted permission to do so in general. Example: a feed reader should not automatically complete the AutoAuth flow for all feeds that prompt for authorization, but initially ask the user about this.

Clients should treat all responses received from authenticated requests as private and unique to the individual user.