token-endpoint
A token endpoint is an HTTP endpoint that Micropub clients can use to obtain an access token given an authorization code. For the most up-to-date information on IndieAuth token endpoints, see the IndieAuth Living Standard.
IndieWeb Examples
- https://tokens.indieauth.com provides tokens as a service, to help implementers bootstrap their micropub support.
- commentpara.de implements its own token endpoint
- Red Wind has its own token endpoint that issues JWT encoded tokens[1]
- Neonblog provides a token endpoint that uses indieauth.com as an auth server. [2]
- Skein provides a token endpoint that issues JWT tokens. [3]
- silo.pub creates JWT encoded tokens based on authorization from its own auth service.
Implementation Notes
Using a token endpoint service
tokens.indieauth.com is a service you can use if you don't want to immediately build your own token endpoint. You can use this token endpoint in production in order to jump-start the development of your own micropub endpoint.
If you later want to switch to hosting your own token endpoint, you can do so without needing to make any changes to micropub clients since they will re-discover your token endpoint each time you sign in.
Creating a token endpoint
Requests will be made to the token endpoint after the client finishes communicating with the authorization server and obtains an auth code.
A token endpoint must be able to both grant an access token as well as verify an access token.
Verifying an Access Token
A micropub endpoint will make a request to the token endpoint to verify that an incoming access token is valid.
- The URL of the token server must be known to the micropub endpoint in advance. The bearer token does not contain any information about the server address.
- This means that the micropub endpoint dictates the token endpoint that the user links to on his homepage.
The micropub endpoint will make a request like the following:
GET https://tokens.indieauth.com/token Authorization: Bearer xxxxxxxx
The token endpoint looks at the token in the authorization header and verifies it. How exactly it does this is up to the implementation, such as in the example below of using either a self-encoded token or a database of tokens. After verifying the token is still valid, the token endpoint returns the information about the token such as the user and scope, in form-encoded or JSON format depending on the HTTP Accept header:
HTTP/1.1 200 OK Content-Type: application/x-www-form-urlencoded me=https://aaronparecki.com/& client_id=https://ownyourgram.com/& scope=create update
HTTP/1.1 200 OK Content-Type: application/json { "me": "https://aaronparecki.com/", "client_id": "https://ownyourgram.com/", "scope": "create update" }
The micropub endpoint will then inspect these values and determine whether to proceed with the request.
Generating an Access Token
At this point, your token endpoint is ready to issue an access token to the app.
How exactly you do this is entirely up to you, and depends on which language/framework you are using. There are multiple ways to generate and later verify an access token.
Since your token endpoint will be issuing the token, and your Micropub endpoint will be the only thing that needs to validate tokens, how that works is entirely up to you, and can even be changed later without any ill effects.
Token Database
A trivial way of creating access tokens is to use a database such as MySQL, Postgres, or Redis. Using this method, you would simply generate a long random string, and use that as a unique key, adding in the rest of the information about the token.
At a minimum, you would store the following data along with the token:
me
client_id
scope
While this is a simple way of handling access tokens, you will quickly realize the limitations. Unless you have a way of expiring and re-issuing tokens, your token database will quickly grow in size and may eventually become unwieldy. Of course this also assumes that your website has a database to begin with, which is not necessarily a safe assumption.
Self-Encoded Tokens
Self-encoded tokens are a way to create access tokens that doesn't require storing a string in a database in order to look it up later. By encoding all of the token information into the token itself, the server can verify the token just by inspecting it later. There are many ways to self-encode tokens, again this depends on your preferences.
One way to create self-encoded tokens is to create a JSON-serialized representation of all the data you want to include in the token, and sign the resulting string with a key known only to your server.
The example below is written in PHP, but the idea applies to any language.
$token_data = array( 'me' => $_POST['me'], 'client_id' => $_POST['client_id'], 'scope' => $auth['scope'], // Returned by the auth code verification step 'date_issued' => date('Y-m-d H:i:s'), 'nonce' => mt_rand(1000000,pow(2,31)) );
In the example above, we've included a few pieces of information that will be useful when decrypting and verifying the token later.
me
- Naturally we need to know which user this token corresponds to.client_id
- Indicates the app that generated the token.scope
- The Micropub endpoint must be able to know what scope the token includes, so it can allow or deny specific requests.date_issued
- Included so that we can selectively invalidate tokens created before a certain date if needed. Also servers to add more entropy to the encrypted string.nonce
- Adds some extra entropy to the encrypted string.
All of this data is then JSON-encoded and encrypted using the "JWT" package, which results in a string that is the access token.
$token = JWT::encode($token_data, $encryption_key);
Discussion
Asking the token endpoint to invalidate a token
Should there be a way to ask the endpoint to invalidate/cancel a previously requested token? E.g. a user could select a log-out button in their Micropub client and the client would then ask the token endpoint to invalidate its specific token.
Currently users of external token endpoints will have to manage token blocklists on the token-accepting end of the chain, e.g. inside their Micropub server. Is it a good idea to have a standard that splits up the token management that way?
- π¬ Martijn van der Ven: I realise this can be solved by hosting your own token-endpoint, but that feels counter intuitive to the idea of using interchangeable token services. On the other hand, making this part of the spec makes managing a stateless token-endpoint a lot harder (nay impossible?).
On IRC Aaron Parecki notes the existence of RFC 7009 for Token Revocation within OAuth. A revocation according to that spec may be handled through a request like:
POST https://tokens.indieauth.com/token Content-Type: application/x-www-form-urlencoded token=xxxxxxxx
The spec defines a new token revocation endpoint, but leaves the method of discovering the endpoint out of scope of the spec. For IndieAuth, we could either reuse the existing token endpoint, since a POST request with a token
parameter is not currently used for anything else, or we could more explicitly make a "new endpoint" by appending a query string parameter to the token endpoint such as action=revoke
.
In that case, the IndieAuth extension to RFC7009 would say that the token revocation endpoint is found by taking the rel=token_endpoint
URL and appending a query string parameter action=revoke
.