Please check the errata for any errors or issues reported since publication.
License: Per CC0, to the extent possible under law, the editor(s) and contributors have waived all copyright and related or neighboring rights to this work. In addition, the editor(s) and contributors have made this specification available under the Open Web Foundation Agreement Version 1.0.
IndieAuth is an identity layer on top of OAuth 2.0 [RFC6749], primarily used to obtain an OAuth 2.0 Bearer Token [RFC6750] for use by [Micropub] clients. End-Users and Clients are all represented by URLs. IndieAuth enables Clients to verify the identity of an End-User, as well as to obtain an access token that can be used to access resources under the control of the End-User.
This document was published by the IndieWeb community as a Living Standard.
Per CC0, to the extent possible under law, the editor(s) and contributors have waived all copyright and related or neighboring rights to this work. In addition, the editor(s) and contributors have made this specification available under the Open Web Foundation Agreement Version 1.0.
This section is non-normative.
The IndieAuth spec began as a way to obtain an OAuth 2.0 access token for use by Micropub clients. It can be used to both obtain an access token, as well as authenticate users signing to any application. It is built on top of the OAuth 2.0 framework, and while this document should provide enough guidance for implementers, referring to the core OAuth 2.0 spec can help answer any remaining questions. More information can be found on the IndieWeb wiki.
IndieAuth builds upon the OAuth 2.0 [RFC6749] Framework as follows
client_secret
is used)Additionally, the parameters defined by OAuth 2.0 (in particular state
, code
, and scope
) follow the same syntax requirements as defined by Appendix A of OAuth 2.0 [RFC6749].
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119].
An IndieAuth implementation can implement one or more of the roles of an IndieAuth server or client. This section describes the conformance criteria for each role.
Listed below are known types of IndieAuth implementations.
An IndieAuth Token Endpoint is responsible for generating and verifying OAuth 2.0 Bearer Tokens.
A Micropub client will attempt to obtain an OAuth 2.0 Bearer Token given a URL that allows the discovery of an Authorization Endpoint, and will use the token when making Micropub requests.
An IndieAuth client is a client that is attempting to authenticate a user given a URL that allows the discovery of an Authorization Endpoint, but does not need an OAuth 2.0 Bearer Token.
Users are identified by a [URL]. Profile URLs MUST have either an https
or http
scheme, MUST contain a path component (/
is a valid path), MUST NOT contain single-dot or double-dot path segments, MAY contain a query string component, MUST NOT contain a fragment component, MUST NOT contain a username or password component, and MUST NOT contain a port. Additionally, host names MUST be domain names and MUST NOT be ipv4 or ipv6 addresses.
Some examples of valid profile URLs are:
https://example.com/
https://example.com/username
https://example.com/users?id=100
Some examples of invalid profile URLs are:
example.com
mailto:user@example.com
https://example.com/foo/../bar
https://example.com/#me
https://user:pass@example.com/
https://example.com:8443/
https://172.28.92.51/
Clients are identified by a [URL]. Client identifier URLs MUST have either an https
or http
scheme, MUST contain a path component, MUST NOT contain single-dot or double-dot path segments, MAY contain a query string component, MUST NOT contain a fragment component, MUST NOT contain a username or password component, and MAY contain a port. Additionally, host names MUST be domain names or a loopback interface and MUST NOT be IPv4 or IPv6 addresses except for IPv4 127.0.0.1
or IPv6 [::1]
.
Since IndieAuth uses https/http URLs which fall under what [URL] calls "Special URLs", a string with no path component is not a valid [URL]. As such, if a URL with no path component is ever encountered, it MUST be treated as if it had the path /
. For example, if a user provides https://example.com
for Discovery, the client MUST transform it to https://example.com/
when using it and comparing it.
Since domain names are case insensitive, the host component of the URL MUST be compared case insensitively. Implementations SHOULD convert the host to lowercase when storing and using URLs.
For ease of use, clients MAY allow users to enter just the host part of the URL, in which case the client MUST turn that into a valid URL before beginning the IndieAuth flow, by prepending either an http
or https
scheme and appending the path /
. For example, if the user enters example.com
, the client transforms it into http://example.com/
before beginning discovery.
This specification uses the link rel registry as defined by [HTML] for both HTML and HTTP link relations.
Clients need to discover a few pieces of information when a user signs in. The client needs to discover the user's indieauth-metadata
endpoint, which provides the location of the IndieAuth server's authorization endpoint and token endpoint, as well as other relevant information for the client. Clients MUST start by making a GET or HEAD request to [Fetch] the user provided URL to discover the necessary values. Clients MUST follow HTTP redirects (up to a self-imposed limit). When using the Authorization flow to obtain an access token for use at another endpoint, such as a [Micropub] endpoint, the client will also discover the micropub
endpoint.
Clients MUST check for an HTTP Link
header [RFC8288] with a rel
value of indieauth-metadata
. If the content type of the document is HTML, then the client MUST check for an HTML <link>
element with a rel
value of indieauth-metadata
. If more than one of these is present, the first HTTP Link
header takes precedence, followed by the first <link>
element in document order.
The URLs discovered MAY be relative URLs, in which case the client MUST resolve them relative to the current document URL according to [URL].
Clients MAY initially make an HTTP HEAD request [RFC7231] to follow redirects and check for the Link
header before making a GET request.
In the event there is no indieauth-metadata
URL provided, for compatibility with previous revisions of IndieAuth, the client SHOULD look for an HTTP Link
header and HTML <link>
element with a rel
value of authorization_endpoint
(and optionally token_endpoint
) following the same order of predence as described above.
Note that the recommendation of looking for the rel=authorization_endpoint
and rel=token_endpoint
are included for backwards compatibility with previous IndieAuth profiles and may be removed from this specification in the future after wide enough adoption of the newer indieauth-metadata
discovery method.
IndieAuth metadata adopts OAuth 2.0 Authorization Server Metadata [RFC8414], with the notable difference that discovery of the URL happens via the IndieAuth link relation rather than the .well-known
discovery method specified by RFC8414. For compatibility with other OAuth 2.0 implementations, use of the .well-known
path as defined in RFC8414 is RECOMMENDED but optional.
The metadata endpoint returns information about the server as a JSON object with the following properties:
issuer
- The server's issuer identifier. The issuer identifier is a URL that uses the "https" scheme and has no query or fragment components. The identifier MUST be a prefix of the indieauth-metadata
URL. e.g. for an indieauth-metadata
endpoint https://example.com/.well-known/oauth-authorization-server
, the issuer URL could be https://example.com/
, or for a metadata URL of https://example.com/wp-json/indieauth/1.0/metadata
, the issuer URL could be https://example.com/wp-json/indieauth/1.0
authorization_endpoint
- The Authorization Endpointtoken_endpoint
- The Token Endpointintrospection_endpoint
- The Introspection Endpointintrospection_endpoint_auth_methods_supported
(optional) - JSON array containing a list of client authentication methods supported by this introspection endpoint.
revocation_endpoint
(optional) - The Revocation Endpointrevocation_endpoint_auth_methods_supported
(optional) - JSON array containing the value "none"
. If a revocation endpoint is provided, this property should also be provided with the value ["none"]
, since the omission of this value defaults to client_secret_basic
according to [RFC8414].scopes_supported
(recommended) - JSON array containing scope values supported by the IndieAuth server. Servers MAY choose not to advertise some supported scope values even when this parameter is used.response_types_supported
(optional) - JSON array containing the response_type values supported. This differs from [RFC8414] in that this parameter is OPTIONAL and that, if omitted, the default is code
grant_types_supported
(optional) - JSON array containing grant type values supported. If omitted, the default value differs from [RFC8414] and is authorization_code
service_documentation
(optional) - URL of a page containing human-readable information that developers might need to know when using the server. This might be a link to the IndieAuth spec or something more personal to your implementation.
code_challenge_methods_supported
- JSON array containing the methods supported for PKCE. This parameter differs from [RFC8414] in that it is not optional as PKCE is REQUIRED.authorization_response_iss_parameter_supported
(optional) - Boolean parameter indicating whether the authorization server provides the iss
parameter. If omitted, the default value is false. As the iss
parameter is REQUIRED, this is provided for compatibility with OAuth 2.0 servers implementing the parameter.userinfo_endpoint
(optional) - The User Info EndpointHTTP/1.1 200 OK Content-Type: application/json { "issuer": "https://indieauth.example.com/", "authorization_endpoint": "https://indieauth.example.com/auth", "token_endpoint": "https://indieauth.example.com/token", "code_challenge_methods_supported": ["S256"] }
When an authorization server presents its authorization interface, it will often want to display some additional information about the client beyond just the client_id
URL, in order to better inform the user about the request being made. Additionally, the authorization server needs to know the list of redirect URLs that the client is allowed to redirect to.
Since client identifiers are URLs, the authorization server SHOULD [Fetch] the URL to find more information about the client.
If the client_id
contains the permitted IPv4 and IPv6 addresses 127.0.0.1
or [::1]
, or if the domain name resolves to these addresses, the authorization endpoint MUST NOT fetch the client_id
.
Note that the server may want to perform some additional checks on the client_id
before fetching it to avoid SSRF attacks. In particular, the server may want to resolve the domain name first and avoid fetching the document if the IP address is within the loopback range defined by [RFC5735] or any other implementation-specific internal IP address.
Clients SHOULD have a web page at their client_id
URL with basic information about the application, at least the application's name and icon. This page serves as a good landing page for human visitors, but can also serve as the place to include machine-readable information about the application. The HTML on the client_id
URL SHOULD be marked up with [h-app] Microformat to indicate the name and icon of the application. Authorization servers SHOULD support parsing the [h-app] Microformat from the client_id
, and if there is an [h-app] with a url
property matching the client_id
URL, then it should use the name and icon and display them on the authorization prompt.
<div class="h-app">
<img src="/logo.png" class="u-logo">
<a href="/" class="u-url p-name">Example App</a>
</div>
This can be parsed with a Microformats2 parser, which will result in the following JSON structure.
{
"type": [
"h-app"
],
"properties": {
"name": ["Example App"],
"logo": ["https://app.example.com/logo.png"],
"url": ["https://app.example.com/"]
}
}
If a client wishes to use a redirect URL that has a different host than their client_id
, or if the redirect URL uses a custom scheme (such as when the client is a native application), then the client will need to explicitly list those redirect URLs so that authorization endpoints can be sure it is safe to redirect users there. The client SHOULD publish one or more <link>
tags or Link
HTTP headers with a rel
attribute of redirect_uri
at the client_id
URL.
Authorization endpoints verifying that a redirect_uri
is allowed for use by a client MUST look for an exact match of the given redirect_uri
in the request against the list of redirect_uri
s discovered after resolving any relative URLs.
GET / HTTP/1.1
Host: app.example.com
HTTP/1.1 200 Ok
Content-type: text/html; charset=utf-8
Link: <https://app.example.com/redirect>; rel="redirect_uri"
<!doctype html>
<html>
<head>
<link rel="redirect_uri" href="/redirect">
</head>
...
</html>
After obtaining a URL from the End-User, and optionally applying URL Canonicalization to it, the client fetches the URL and looks for the indieauth-metadata
rel values in the HTTP Link
headers and HTML <link>
tags as described in § 4.1 Discovery by Clients.
Link: <https://indieauth.example.com/.well-known/oauth-authorization-server>; rel="indieauth-metadata" <link rel="indieauth-metadata" href="https://indieauth.example.com/.well-known/oauth-authorization-server">
The client fetches the metadata document and finds the authorization_endpoint
and token_endpoint
in the JSON body.
{ "issuer": "https://indieauth.example.com/", "authorization_endpoint": "https://indieauth.example.com/auth", "token_endpoint": "https://indieauth.example.com/token", "code_challenge_methods_supported": ["S256"] }
Refresh tokens are issued to the client by the authorization server and MAY be used at any time to obtain a new access token, usually when the current access token becomes invalid or expires, or to obtain a new token with identical or narrower scope (access tokens may have a shorter lifetime and fewer permissions than authorized by the resource owner).
Use of short-lived access tokens and the offering of refresh tokens is RECOMMENDED, however, issuing a refresh token is at the discretion of the authorization server, and may be issued based on properties of the client, properties of the request, policies within the authorization server, a choice by the user authorizing the request or any other criteria. If the authorization server issues a refresh token, it is included in the return when issuing an access token. If the authorization server decides not to issue refresh tokens, or the refresh token expires, the client MAY obtain new access tokens by starting the authorization flow over.
Authorization servers MAY revoke refresh tokens automatically in case of a security event, such as a password change or a logout at the authorization server, or when they are redeemed, in which case a new refresh token MAY be provided. Refresh tokens SHOULD expire if the client has been inactive for some time, i.e., the refresh token has not been used to obtain fresh access tokens for some time. The expiration time is at the discretion of the authorization server.
To refresh an access token, the client makes a POST request to the token endpoint to exchange the refresh token for the new access token. The POST request contains the following parameters:
grant_type=refresh_token
refresh_token
- The refresh token previously offered to the client.client_id
- The client ID that was used when the refresh token was issued.scope
(optional) - The client may request a token with the same or fewer scopes than the original access token. If omitted, is treated as equal to the original scopes granted.For example:
POST https://example.org/token Content-type: application/x-www-form-urlencoded Accept: application/json grant_type=refresh_token &refresh_token=xxxxxxxx&client_id=https://app.example.com
If valid and authorized, the authorization server issues an access token as noted in Access Token Response. The authorization server MAY issue a new refresh token, in which case the client MUST discard the old refresh token and replace it with the new refresh token. The authorization server MAY revoke the old refresh token after issuing a new refresh token to the client. If a new refresh token is issued, the refresh token scope MUST be identical to that of the refresh token included by the client in the request.
Refresh tokens SHOULD expire if the client has not used the refresh token to obtain new access tokens for some time. The expiration time is at the discretion of the authorization server.
In OAuth 2.0, access tokens are opaque to clients, so clients do not need to know anything about the contents or structure of the token itself. Additionally, endpoints that clients make requests to, such as [Micropub] endpoints, may not even understand how to interpret tokens if they were issued by a standalone token endpoint. If the token endpoint is not tightly integrated with the resource server the client is interacting with, then the resource server needs a way to verify access tokens that it receives from clients. If the token endpoint and Micropub endpoint are tightly coupled, then they can of course use an internal mechanism to verify access tokens.
Token endpoints that intend to interoperate with other endpoints MUST use the mechanism described below to allow resource servers such as Micropub endpoints to verify access tokens.
If a resource server needs to verify that an access token is valid, it may do so using Token Introspection. IndieAuth extends OAuth 2.0 Token Introspection [RFC7662] by adding that the introspection response MUST include an additional parameter, me
.
Note that the request to the endpoint will not contain any user-identifying information, so the resource server (e.g. Micropub endpoint) will need to know via out-of-band methods which token endpoint is in use.
The resource server SHOULD make a POST request to the token endpoint containing the Bearer token in the token
parameter, which will generate a token verification response. The endpoint MUST also require some form of authorization to access this endpoint and MAY identify that in the introspection_endpoint_auth_methods_supported
parameter of the metadata response. If the authorization is insufficient for the request, the authorization server MUST respond with an HTTP 401 code.
POST https://indieauth.example.com/introspect Content-type: application/x-www-form-urlencoded Accept: application/json Authorization: Bearer xxxxxxxx token=xxxxxxxx
The token endpoint verifies the access token (how this verification is done is up to the implementation), and returns information about the token:
active
- (required) Boolean indicator of whether or not the presented token is currently activeme
- (required) The profile URL of the user corresponding to this tokenclient_id
- The client ID associated with this tokenscope
- A space-separated list of scopes associated with this tokenexp
- (optional) Integer timestamp, measured in the number of seconds since January 1 1970 UTC, indicating when this token will expireiat
- (optional) Integer timestamp, measured in the number of seconds since January 1 1970 UTC, indicating when this token was originally issuedHTTP/1.1 200 OK Content-Type: application/json { "active": true, "me": "https://user.example.net/", "client_id": https://app.example.com/", "scope": "create update delete" "exp": 1632443647, "iat": 1632443147 }
Specific implementations MAY include additional parameters as top-level JSON properties. Clients SHOULD ignore parameters they don't recognize.
If the token is not valid, the endpoint still MUST return a 200 Response, with the only parameter being `active` (with its value set to false
). The response SHOULD NOT include any additional information about an inactive token, including why the token is inactive.
HTTP/1.1 200 OK Content-Type: application/json { "active": false, }
A client may wish to explicitly disable an access token that it has obtained, such as when the user signs out of the client. IndieAuth implements OAuth 2.0 Token Revocation [RFC7009] using the revocation endpoint defined in the server metadata:
An example revocation request is below.
POST https://indieauth.example.com/revocation HTTP/1.1 Content-Type: application/x-www-form-urlencoded Accept: application/json token=xxxxxxxx
As described in [RFC7009], the revocation endpoint responds with HTTP 200 for both the case where the token was successfully revoked, or if the submitted token was invalid.
A previous version of the spec used the token endpoint as the revocation endpoint with the additional parameter action=revoke
. Servers that wish to support older versions of clients may wish to retain this behavior for backwards compatibility.
The client accesses protected resources by presenting the access token to the resource server. The resource server MUST validate the access token and ensure that it has not expired and that its scope covers the requested resource.
When a request fails, the resource server responds using the appropriate HTTP status codes, and includes one of the following error codes in the response:
"invalid_request"
- The request is not valid. The resource server SHOULD respond with HTTP 400"invalid_token"
- The access token provided is expired, revoked, or invalid. The resource server SHOULD respond with HTTP 401"insufficient_scope"
- The request requires higher privileges than provided. The resource server SHOULD respond with HTTP 403If the requests lacks any authentication information, the resource server SHOULD NOT include an error code or other information.
A client may wish to refresh or receive additional information about the authenticated end user outside of the authorization response. To fetch the user's profile information, the client makes a GET request to the userinfo endpoint, providing an access token that was issued with the profile
and/or email
scopes.
GET /userinfo HTTP/1.1 Host: indieauth.example.com Authorization: Bearer xxxxxxxxxxx
The authorization server returns a JSON [RFC7159] object identical to the profile property identified in Profile Information when a response_type
value is used that results in an access token being issued and would require the same profile
or email
scopes. The considerations identified in Profile Information regarding the non-authoritative nature of the information would also apply here.
If the request lacks a provided access token, or the token does not contain appropriate scopes, the endpoint SHOULD respond with an error response as noted in Accessing Protected Resources.
Like the return of profile information in the authorization response, implementation of the userinfo endpoint is entirely optional. If implemented, discovery would be through the userinfo_endpoint
property in the authorization server metadata document.
HTTP/1.1 200 OK Content-Type: application/json { "name": "Example User", "url": "https://user.example.net/", "photo": "https://user.example.net/photo.jpg", "email": "user@example.net" }
In addition to the security considerations in OAuth 2.0 Core [RFC6749] and OAuth 2.0 Threat Model and Security Considerations [RFC6819], the additional considerations apply.
Authorization servers SHOULD fetch the client_id
provided in the authentication or authorization request in order to provide users with additional information about the request, such as the application name and logo. If the server does not fetch the client information, then it SHOULD take additional measures to ensure the user is provided with as much information as possible about the request.
The authorization server SHOULD display the full client_id
on the authorization interface, in addition to displaying the fetched application information if any. Displaying the client_id
helps users know that they are authorizing the expected application.
Since all IndieAuth clients are public clients, and no client authentication is used, the only measure available to protect against some attacks described in [RFC6819] is strong verification of the client's redirect_uri
. If the redirect_uri
scheme, host or port differ from that of the client_id
, then the authorization server MUST either verify the redirect URL as described in Redirect URL, or display the redirect URL to the user so they can inspect it manually.
The link relation types below are documented to be registered by IANA per Section 6.2.1 of [RFC8288]:
This section is non-normative.
This section is non-normative.
You can find a list of articles about IndieAuth on the IndieWeb wiki.
This section is non-normative.
You can find a list of IndieAuth implementations on indieauth.net
The editor wishes to thank the IndieWeb community and other implementers for their contributions, support, encouragement and enthusiasm, including but not limited to: Angelo Gladding, Amy Guy, Barnaby Walters, Benjamin Roberts, Bret Comnes, Christian Weiske, David Shanske, David Somers, Dmitri Shuralyov, Fluffy, François Kooman, Jamie Tanna, Jeena Paradies, Manton Reece, Martijn van der Ven, Sebastiaan Andeweg, Sven Knebel, and Tantek Çelik.
This section is non-normative.
userinfo
endpoint to fetch updated profile dataiss
parameter to the authorization responseme
value returned by the authorization server is a profile URL, do not refer to the user provided URL as suchme
parameter optional (but recommended) in the authorization requestresponse_type=code
and make it required, to bring it in line with OAuth 2.0grant_type=authorization_code
when redeeming the authorization code at the authorization endpointme
parameter from the token endpoint request