IndieAuth
IndieAuth
IndieWeb Living Standard 11 July 2024
This version:
Test suite:
Previous version:
Editor:
Aaron Parecki
Repository:
Github
Issues
Commits
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
Abstract
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.
Author's Note
This section is non-normative.
This specification was contributed to the
W3C
from the
IndieWeb
community. More
history and evolution of IndieAuth can be found on the
IndieWeb wiki
Status of This Document
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
1.
Introduction
1.1
Background
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
1.2
OAuth 2.0 Extension
IndieAuth builds upon the OAuth 2.0 [
RFC6749
] Framework as follows
Specifies a format for user identifiers (a resolvable URL)
Specifies a method of discovering the IndieAuth metadata (containing the authorization and token endpoints) given a user's profile URL
Specifies a format for the Client ID (a resolvable URL containing client metadata)
Client registration at the authorization endpoint is not necessary, since client IDs are resolvable URLs
Redirect URL registration happens by verifying data fetched at the Client ID URL
Specifies a mechanism for returning the user identifier and profile information for the user who authorized a request
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
].
2.
Conformance
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
].
2.1
Conformance Classes
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.
2.1.1
Authorization Endpoint
An IndieAuth Authorization Endpoint is responsible for obtaining authentication or authorization consent from the end user and generating and verifying authorization codes.
2.1.2
Token Endpoint
An IndieAuth Token Endpoint is responsible for generating and verifying OAuth 2.0 Bearer Tokens.
2.1.3
Micropub Client
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.
2.1.4
IndieAuth Client
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.
3.
Identifiers
3.1
Issuer Identifier
The issuer identifier of the authorization server, which is primarily used to prevent authorization server mix-up attacks. The issuer identifier is a URL that uses the "https" scheme and has no query or fragment components as defined in [
RFC9207
], however, the identifier
MUST
also be a prefix of the
indieauth-metadata
URL. For example, for an
indieauth-metadata
endpoint
, the issuer URL could be
, or for a metadata URL of
, the issuer URL could be
3.2
User Profile URL
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:
Some examples of invalid profile URLs are:
example.com
- missing scheme
mailto:user@example.com
- invalid scheme
- contains a double-dot path segment
- contains a fragment
- contains a username and password
- contains a port
- host is an IP address
3.3
Client Identifier
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]
3.4
URL Canonicalization
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
for Discovery, the client
MUST
transform it to
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
before beginning discovery.
4.
Discovery
This specification uses the link rel registry as defined by [
HTML
for both HTML and HTTP link relations.
4.1
Discovery by Clients
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
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
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
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.
4.1.1
IndieAuth Server Metadata
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.
authorization_endpoint
- The Authorization Endpoint
token_endpoint
- The Token Endpoint
introspection_endpoint
- The Introspection Endpoint
introspection_endpoint_auth_methods_supported
(optional) - JSON array containing a list of client authentication methods supported by this introspection endpoint.
revocation_endpoint
(optional) - The Revocation Endpoint
revocation_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 Endpoint
Example
HTTP/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"]
4.2
Client Information Discovery
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.
Clients
SHOULD
publish an OAuth Client ID Metadata Document [
ClientIDMetadataDocument
] at the client identifier URL.
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.
4.2.1
Client Metadata
This section is based on [
ClientIDMetadataDocument
], and is included here for convenience, but the normative requirements in [
ClientIDMetadataDocument
] take precedence.
Clients
SHOULD
have a JSON [
RFC7159
] document at their
client_id
URL containing client metadata defined in [
RFC7591
], the minimum properties for an IndieAuth client defined below. The authorization server
MAY
cache the client metadata it discovers at the client ID URL and
SHOULD
respect cache-control headers and set reasonable defaults if none are present.
client_id
- the client identifier. The authorization server
MUST
verify that the
client_id
in the document matches the
client_id
of the URL where the document was retrieved. The
client_uri
MUST
be a prefix of the
client_id
client_name
- (optional) Human readable name of the client to be presented on the consent screen
client_uri
- URL of a webpage providing information about the client
logo_uri
- (optional) URL that references a logo or icon for the client
redirect_uris
- (optional) An array of redirect URIs
Additional metadata properties defined in [
ClientMetadata
MAY
be added, with the understanding that some authorization servers may not recognize them.
Clients
SHOULD
have a web page at their
client_uri
URL with basic information about the application, at least the application's name and icon. Authorization servers
SHOULD
display this URL to the user during authorization, so that the user can learn more about the application. Authorization servers
SHOULD
warn the user if the hostname of the
client_uri
is different from the hostname of the
client_id
Note: Earlier versions of this specification recommended an HTML document with
h-app
Microformats as the
client_id
, and authorization servers may wish to continue to support this for backwards compatibility.
4.2.2
Redirect URL
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 in the
redirect_uri
property of the client metadata so that authorization endpoints can be sure it is safe to redirect users there. 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 after resolving any relative URLs.
When a client chooses to serve a web page as its client_id, the client
MAY
publish one or more
tags or
Link
HTTP headers with a
rel
attribute of
redirect_uri
at the
client_id
URL to be used by the authorization server.
Example
GET
HTTP/1.1
Host
app.example.com
HTTP/1.1
200
Ok
Content-type
text/html; charset=utf-8
Link
html
html
head
link
rel
"redirect_uri"
href
"/redirect"
head
...
html
5.
Authorization
This section describes how to authenticate users and optionally obtain an access token using the OAuth 2.0 Authorization Code Flow with IndieAuth.
The End-User enters a URL in the login form of the client and clicks "Sign in". The client canonicalizes the URL.
The client discovers the End-User's IndieAuth server metadata endpoint by fetching the provided URL and looking for the
rel=indieauth-metadata
value
The client discovers the server's authorization endpoint and token endpoint by fetching the metadata URL and looking for the
authorization_endpoint
and
token_endpoint
values
The client builds the authorization request including its client identifier, requested scope, local state, and a redirect URI, and redirects the browser to the authorization endpoint
The authorization endpoint fetches the client information from the client identifier URL in order to have an application name and icon to display to the user
The authorization endpoint verifies the End-User, e.g. by logging in, and establishes whether the End-User grants or denies the client's request
The authorization endpoint generates an authorization code and redirects the browser back to the client, including an authorization code in the URL
The client exchanges the authorization code for an access token by making a POST request to the token endpoint. The token endpoint validates the authorization code, and responds with the End-User's canonical profile URL and an access token
The client confirms the returned profile URL declares the same authorization server and accepts the profile URL
Note: If the client is only trying to learn who the user is and does not need an access token, the client exchanges the authorization code for the user profile information at the Authorization Endpoint instead.
5.1
Discovery
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
tags as described in
4.1
Discovery by Clients
Example
Link:
The client fetches the metadata document and finds the
authorization_endpoint
and
token_endpoint
in the JSON body.
Example
"issuer": "https://indieauth.example.com/",
"authorization_endpoint": "https://indieauth.example.com/auth",
"token_endpoint": "https://indieauth.example.com/token",
"code_challenge_methods_supported": ["S256"]
5.2
Authorization Request
The client builds the authorization request URL by starting with the discovered
authorization_endpoint
URL and adding parameters to the query component.
All IndieAuth clients
MUST
use PKCE ([
RFC7636
]) to protect against authorization code injection and CSRF attacks. A non-canonical description of the PKCE mechanism is described below, but implementers should refer to [
RFC7636
] for details.
Clients use a unique secret per authorization request to protect against authorization code injection and CSRF attacks. The client first generates this secret, which it can later use along with the authorization code to prove that the application using the authorization code is the same application that requested it.
The client first creates a code verifier for each authorization request by generating a random string using the characters
[A-Z] / [a-z] / [0-9] / - / . / _ / ~
with a minimum length of 43 characters and maximum length of 128 characters. This value is stored on the client and will be used in the authorization code exchange step later.
The client then creates the code challenge derived from the code verifier by calculating the SHA256 hash of the code verifier and
Base64-URL-encoding
the result.
code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
For backwards compatibility, authorization endpoints
MAY
accept authorization requests without a code challenge if the authorization server wishes to support older clients.
response_type=code
- Indicates to the authorization server that an authorization code should be returned as the response
client_id
- The client URL
redirect_uri
- The redirect URL indicating where the user should be redirected to after approving the request
state
- A parameter set by the client which will be included when the user is redirected back to the client. This is used to prevent CSRF attacks. The authorization server
MUST
return the unmodified state value back to the client.
code_challenge
- The code challenge as previously described.
code_challenge_method
- The hashing method used to calculate the code challenge, e.g. "S256"
scope
- (optional) A space-separated list of scopes the client is requesting, e.g. "profile", or "profile create". If the client omits this value, the authorization server
MUST NOT
issue an access token for this authorization code. Only the user's profile URL may be returned without any scope requested. See
Profile Information
for details about which scopes to request to return user profile information.
me
- (optional) The URL that the user entered
Example
client_id=https://app.example.com/&
redirect_uri=https://app.example.com/redirect&
state=1234567890&
code_challenge=OfYAxt8zU2dAPDWQxTAUIteRzMsoj9QBdMIVEDOErUo&
code_challenge_method=S256&
scope=profile+create+update+delete&
me=https://user.example.net/
The client
SHOULD
provide the
me
query string parameter to the authorization endpoint, either the exact value the user entered, or the value after applying
URL Canonicalization
The authorization endpoint
SHOULD
fetch the
client_id
URL to retrieve application information and the client's registered redirect URLs, see
Client Information Discovery
for more information.
If the URL scheme, host or port of the
redirect_uri
in the request do not match that of the
client_id
, then the authorization endpoint
SHOULD
verify that the requested
redirect_uri
matches one of the
redirect URLs
published by the client, and
SHOULD
block the request from proceeding if not.
It is up to the authorization endpoint how to authenticate the user. This step is out of scope of OAuth 2.0, and is highly dependent on the particular implementation. Some authorization servers use typical username/password authentication, and others use alternative forms of authentication such as [
RelMeAuth
], or delegate to other identity providers.
The authorization endpoint
MAY
use the provided
me
query component as a hint of which user is attempting to sign in, and to indicate which profile URL the client is expecting in the resulting profile URL response or access token response. This is specifically helpful for authorization endpoints where users have multiple supported profile URLs, so the authorization endpoint can make an informed decision as to which profile URL the user meant to identify as. Note that from the authorization endpoint's view, this value as provided by the client is unverified external data and
MUST NOT
be assumed to be valid data at this stage. If the logged-in user doesn't match the provided
me
parameter by the client, the authorization endpoint
MAY
either ignore the
me
parameter completely or display an error, at the authorization endpoint's discretion.
Once the user is authenticated, the authorization endpoint presents the authorization request to the user. The prompt
MUST
indicate which application the user is signing in to, and
SHOULD
provide as much detail as possible about the request, such as information about the requested scopes.
5.2.1
Authorization Response
If the user approves the request, the authorization endpoint generates an authorization code and builds the redirect back to the client.
The redirect is built by starting with the
redirect_uri
in the request, and adding the following parameters to the query component of the redirect URL:
code
- The authorization code generated by the authorization endpoint. The code
MUST
expire shortly after it is issued to mitigate the risk of leaks, and
MUST
be valid for only one use. A maximum lifetime of 10 minutes is recommended. See
OAuth 2.0 Section 4.1.2
for additional requirements on the authorization code.
state
- The state parameter
MUST
be set to the exact value that the client set in the request.
iss
- The issuer identifier for client validation.
Example
HTTP/1.1 302 Found
Location: https://app.example.com/redirect?code=xxxxxxxx&
state=1234567890&
iss=https%3A%2F%2Findieauth.example.com
Upon the redirect back to the client, the client
MUST
verify:
That the
state
parameter in the request is valid and matches the state parameter that it initially created, in order to prevent CSRF attacks. The state value can also store session information to enable development of clients that cannot store data themselves.
That the
iss
parameter in the request is valid and matches the issuer parameter provided by the Server Metadata endpoint during Discovery as outlined in OAuth 2.0 Authorization Server Issuer Identification[
RFC9207
]. Clients
MUST
compare the parameters using simple string comparison. If the value does not match the expected issuer identifier, clients
MUST
reject the authorization response and
MUST NOT
proceed with the authorization grant. For error responses, clients
MUST NOT
assume that the error originates from the intended authorization server.
See OAuth 2.0 [
RFC6749
Section 4.1.2.1
for how to indicate errors and other failures to the user and client.
5.3
Redeeming the Authorization Code
Once the client has obtained an authorization code, it can redeem it for an access token or the user's final profile URL.
5.3.1
Request
If the client needs an access token in order to make requests to a resource server such as a [
Micropub
] endpoint, it can exchange the authorization code for an access token and the user's profile URL at the
token endpoint
If the client only needs to know the user who logged in and does not need to make requests to resource servers with an access token, the client exchanges the authorization code for the user's profile URL at the
authorization endpoint
After the client validates the state parameter, the client makes a POST request to the token endpoint or authorization endpoint to exchange the authorization code for the final user profile URL and/or access token. The POST request contains the following parameters:
grant_type=authorization_code
code
- The authorization code received from the authorization endpoint in the redirect.
client_id
- The client's URL, which
MUST
match the client_id used in the authentication request.
redirect_uri
- The client's redirect URL, which
MUST
match the initial authentication request.
code_verifier
- The original plaintext random string generated before starting the authorization request.
Example request to authorization endpoint
Example
POST https://indieauth.example.com/auth
Content-type: application/x-www-form-urlencoded
Accept: application/json
grant_type=authorization_code
&code=xxxxxxxx
&client_id=https://app.example.com/
&redirect_uri=https://app.example.com/redirect
&code_verifier=a6128783714cfda1d388e2e98b6ae8221ac31aca31959e59512c59f5
Example request to token endpoint
Example
POST https://indieauth.example.com/token
Content-type: application/x-www-form-urlencoded
Accept: application/json
grant_type=authorization_code
&code=xxxxxxxx
&client_id=https://app.example.com/
&redirect_uri=https://app.example.com/redirect
&code_verifier=a6128783714cfda1d388e2e98b6ae8221ac31aca31959e59512c59f5
Note that for backwards compatibility, the authorization endpoint
MAY
allow requests without the
code_verifier
. If an authorization code was issued with no
code_challenge
present, then the authorization code exchange
MUST NOT
include a
code_verifier
, and similarly, if an authorization code was issued with a
code_challenge
present, then the authorization code exchange
MUST
include a
code_verifier
5.3.2
Profile URL Response
If the client only needs to know the user who logged in, the client will exchange the authorization code at the
authorization endpoint
, and only the canonical user profile URL and possibly profile information is returned.
The authorization endpoint verifies that the authorization code is valid, has not yet been used, and that it was issued for the matching
client_id
and
redirect_uri
, and checks that the provided
code_verifier
hashes to the same value as given in the
code_challenge
in the original authorization request. If the request is valid, then the endpoint responds with a JSON [
RFC7159
] object containing the property
me
, with the canonical user profile URL for the user who signed in, and optionally the property
profile
with the user's profile information as defined in
Profile Information
Example
HTTP/1.1 200 OK
Content-Type: application/json
"me": "https://user.example.net/"
The resulting profile URL
MAY
be different from the URL provided to the client for discovery. This gives the authorization server an opportunity to canonicalize the user's URL, such as correcting
http
to
https
, or adding a path if required. See
Differing User Profile URLs
for security considerations client developers should be aware of.
See OAuth 2.0 [
RFC6749
Section 5.2
for how to respond in the case of errors or other failures.
5.3.3
Access Token Response
When the client receives an authorization code that was requested with one or more scopes that will result in an access token being returned, the client will exchange the authorization code at the
token endpoint
The token endpoint needs to verify that the authorization code is valid, and that it was issued for the matching
client_id
and
redirect_uri
, contains at least one
scope
, and checks that the provided
code_verifier
hashes to the same value as given in the
code_challenge
in the original authorization request. If the authorization code was issued with no
scope
, the token endpoint
MUST NOT
issue an access token, as empty scopes are invalid per Section 3.3 of OAuth 2.0 [
RFC6749
].
The specifics of how the token endpoint verifies the authorization code are out of scope of this document, as typically the authorization endpoint and token endpoint are part of the same system and can share storage or another private communication mechanism.
If the request is valid, then the token endpoint can generate an access token and return the appropriate response. The token response is a JSON [
RFC7159
] object containing:
access_token
(required) - the OAuth 2.0 Bearer Token [
RFC6750
].
me
(required) - the canonical user profile URL for the user this access token corresponds to.
profile
(optional) - the user's profile information as defined in
Profile Information
expires_in
(recommended) - The lifetime in seconds of the access token.
refresh_token
(optional) - The refresh token, which can be used to obtain new access tokens as defined in
Refresh Tokens
For example:
Example
10
HTTP/1.1 200 OK
Content-Type: application/json
"access_token": "XXXXXX",
"token_type": "Bearer",
"scope": "create update delete",
"me": "https://user.example.net/"
The resulting profile URL
MAY
be different from the URL provided to the client for discovery. This gives the authorization server an opportunity to canonicalize the user's URL, such as correcting
http
to
https
, or adding a path if required. See
Differing User Profile URLs
for security considerations client developers should be aware of.
See OAuth 2.0 [
RFC6749
Section 5.2
for how to respond in the case of errors or other failures.
5.3.4
Profile Information
Requesting Profile Information
If the client would like to request the user's profile information in addition to confirming their profile URL, the client can include one or more scopes in the initial authorization request. The following
scope
values are defined by this specification to request profile information about the user:
profile
(required) - This scope requests access to the user's default profile information which include the following properties:
name
photo
url
email
- This scope requests access to the user's email address in the following property:
email
Note that because the
profile
scope is required when requesting profile information, the
email
scope cannot be requested on its own and must be requested along with the
profile
scope if desired.
When an authorization code is issued with any of the scopes defined above, then the response when exchanging the authorization code
MAY
include a new property,
profile
, alongside the
me
property in the response from the authorization endpoint or the token endpoint. The
profile
property is defined as a JSON [
RFC7159
] object with the properties defined by each scope above.
For example, a complete response to a request with the scopes
profile email create
, including an access token and profile information, may look like the following:
Example
11
HTTP/1.1 200 OK
Content-Type: application/json
"access_token": "XXXXXX",
"token_type": "Bearer",
"scope": "profile email create",
"me": "https://user.example.net/",
"profile": {
"name": "Example User",
"url": "https://user.example.net/",
"photo": "https://user.example.net/photo.jpg",
"email": "user@example.net"
As is always the case with OAuth 2.0, there is no guarantee that the scopes the client requests will be granted by the authorization server or the user. The client should not rely on the presence of profile information even when requesting the profile scope. As such, implementing support for returning profile information from the authorization server is entirely optional.
The information returned in the
profile
object is informational, and there is no guarantee that this information is "real" or "verified". The information provided is only what the user has chosen to share with the client, and may even vary depending on which client is requesting this data.
name
- Name the user wishes to provide to the client. This is not to be considered by the client to be the full name of the user. Clients are expected to use this as a display name.
url
- URL of the user's website. The
url
is not guaranteed to match the
me
URL, and may even have a different host. For example, a multi-author website may use the website's URL as the
me
URL, but return each specific author's own personal website in the profile data.
photo
- A photo or image that the user wishes clients to use as a profile image.
email
- (if email scope is requested) The email address a user wishes to provide to the client.
The client
MUST NOT
treat the information in the
profile
object as canonical or authoritative, and
MUST NOT
make any authentication or identification decisions based on this information.
For example, attempting to use the
email
returned in the profile object as a user identifier will lead to security holes, as any user can create an authorization endpoint that returns any email address in the profile response. A client using the email address returned here should treat it the same as if it had been hand-entered in the client application and go through its own verification process before using it.
5.4
Authorization Server Confirmation
Clients will initially prompt the user to enter a URL in order to discover the necessary endpoints to perform authentication or authorization. However, there may be differences between the URL that the user initially enters and the final resulting profile URL as returned by the authorization server. The differences may be anything from a differing scheme (http vs https), to even a URL with a different host.
Upon receiving the
me
URL in the response from the authorization server (either in the
profile URL response
or
access token response
) the client
MUST
verify the authorization server is authorized to make claims about the profile URL returned by confirming the returned profile URL declares the same authorization server.
The client
MUST
perform
endpoint discovery
on the returned
me
URL and verify that URL declares the same authorization endpoint as was discovered in the initial discovery step,
unless
the returned
me
URL is an exact match of the initially entered URL or any of the URLs encountered during the
initial endpoint discovery
, either from a possible redirect chain or as the final value.
Note that the step of checking for the existence of the returned profile URL in the initial endpoint discovery is an optional optimization step which may save the client from possibly needing to make another HTTP request. This step may be skipped for simplicity, as discovering the authorization server from the returned profile URL is sufficient to confirm the returned profile URL declares the same authorization server.
This verification step ensures that an authorization endpoint is not able to issue valid responses for arbitrary profile URLs, and that users on a shared domain cannot forge authorization on behalf of other users of that domain.
Examples
The following are some non-normative examples of real-world scenarios in which the initial user-entered URL may be different from the final resulting profile URL returned by the authorization server.
Basic Redirect
The basic redirect example covers cases such as:
entering a domain with a www prefix and resolving it to the main domain
entering a URL with no scheme or with http and resolving it to an https URL
entering a short domain and resolving it to a different longer domain
Steps
The user enters
www.example.com
into the client
The client applies the steps from URL canonicalization to turn it into a URL:
The client makes a GET request to
The server returns a 301 redirect to
The client makes a GET request to
and finds the authorization endpoint
The client does the IndieAuth flow with that authorization endpoint. This results in the profile URL response with a
me
value of
as the canonical Profile URL.
The client sees that the canonical Profile URL matches the URL that the authorization endpoint was discovered at, and accepts the value
Service Domain to Subdomain
The user enters
example.com
into the client
The client applies the steps from URL canonicalization to turn it into a URL:
The client makes a GET request to
The server returns a 301 redirect to
The client makes a GET request to
and finds the authorization endpoint,
The client does the IndieAuth flow with
. This results in the profile URL response with a
me
value of
as the canonical Profile URL.
This is the first time the client has seen this URL, so must verify the relationship between this subdomain and the authorization server. It fetches
and finds the same authorization endpoint
The client accepts the
me
value of
Service Domain to Path
The user enters
example.com
into the client
The client applies the steps from URL canonicalization to turn it into a URL:
The client makes a GET request to
The server returns a 301 redirect to
The client makes a GET request to
and finds the authorization endpoint,
The client does the IndieAuth flow with
. This results in the profile URL response with a
me
value of
as the canonical Profile URL.
This is the first time the client has seen this URL, so must verify the relationship between this subdomain and the authorization server. It fetches
and finds the same authorization endpoint
The client accepts the
me
value of
Email-like Identifier
The user enters
user@example.com
into the client
The client applies the steps from URL canonicalization to turn it into a URL:
The client makes a GET request to
providing the HTTP Basic Auth username
user
The server returns a 301 redirect to
The client makes a GET request to
and finds the authorization endpoint,
Note: Alternatively the server can advertise the authorization endpoint in the response to the
request directly instead of needing a separate redirect
The client does the IndieAuth flow with
, providing the user-entered
user@example.com
in the request as a hint to the server. This results in the profile URL response with a
me
value of
as the canonical Profile URL.
This is the first time the client has seen this URL, so must verify the relationship between this subdomain and the authorization server. It fetches
and finds the same authorization endpoint
The client accepts the
me
value of
5.5
Refresh Tokens
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.
5.5.1
Refreshing an Access Token
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:
Example
12
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.
6.
Access Token Verification
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.
6.1
Access Token Verification Request
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.
Example
13
POST https://indieauth.example.com/introspect
Content-type: application/x-www-form-urlencoded
Accept: application/json
Authorization: Bearer xxxxxxxx
token=xxxxxxxx
6.2
Access Token Verification Response
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 active
me
- (required) The profile URL of the user corresponding to this token
client_id
- The client ID associated with this token
scope
- A space-separated list of scopes associated with this token
exp
- (optional) Integer timestamp, measured in the number of seconds since January 1 1970 UTC, indicating when this token will expire
iat
- (optional) Integer timestamp, measured in the number of seconds since January 1 1970 UTC, indicating when this token was originally issued
Example
14
HTTP/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.
Example
15
HTTP/1.1 200 OK
Content-Type: application/json
"active": "false",
7.
Token Revocation
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:
7.1
Token Revocation Request
An example revocation request is below.
Example
16
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.
8.
Accessing Protected Resources
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.
8.1
Error Responses
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 403
If the requests lacks any authentication information, the resource server
SHOULD NOT
include an error code or other information.
9.
User 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.
Example
17
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.
Example
18
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"
10.
Security Considerations
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.
10.1
Preventing Phishing and Redirect Attacks
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 IndieAuth clients are likely to be public clients (if no
jwks_uri
is advertised in the client metatadata), 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.
11.
IANA Considerations
The link relation types below are documented to be registered by IANA per Section 6.2.1 of [
RFC8288
]:
Relation Name:
indieauth-metadata
Description:
Used for discovery of the OAuth 2.0 metadata document given an IndieAuth profile URL.
Reference:
IndieAuth Specification (https://indieauth.spec.indieweb.org/)
Relation Name:
redirect_uri
Description:
Used for an authorization server to discover the OAuth 2.0 redirect URI for a client given the client's IndieAuth client ID.
Reference:
IndieAuth Specification (https://indieauth.spec.indieweb.org/)
A.
Resources
This section is non-normative.
More IndieAuth resources
Implementation guide for obtaining an access token using IndieAuth
Implementation guide for authenticating users without obtaining an access token
A.1
Articles
This section is non-normative.
You can find a list of
articles about IndieAuth
on the IndieWeb wiki.
A.2
Implementations
This section is non-normative.
You can find a list of
IndieAuth implementations
on indieauth.net
B.
Acknowledgements
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, Emelia Smith, Fluffy, François Kooman, Jamie Tanna, Jeena Paradies, Manton Reece, Martijn van der Ven, Sebastiaan Andeweg, Sven Knebel, and Tantek Çelik.
C.
Change Log
This section is non-normative.
C.1
Changes from 12 February 2022 to this version
Client metadata discovery now happens via JSON rather than Microformats, referencing OAuth Client ID Metadata Document
Fixes and editorial changes
C.2
Changes from 26 November 2020 to 12 February 2022
IndieAuth servers now use OAuth Server Metadata to publish their endpoints, and user profile URLs should link to the metadata document instead of the individual authorization endpoint and token endpoint
Defines the revocation endpoint in the server metadata instead of overriding the token endpoint
Defines token introspection as a new endpoint and new response format instead of overriding the token endpoint
Adds a new
userinfo
endpoint to fetch updated profile data
Adds the OAuth 2.0
iss
parameter to the authorization response
Adds a section describing refresh token usage. (Note that this was always possible in IndieAuth, but many people didn't know it was an option because it wasn't described here.)
Fixed redirect URL example in Authorization Response
Clarifications around the use of the profile scope in profile response and token response
Note that the authorization server must not fetch the client_id URL if it's a localhost URL
C.3
Changes from 26 September 2020 to 26 November 2020
Remove same-domain requirement for entered and final profile URL by instead having the client
confirm the authorization server
Only the
me
value returned by the authorization server is a profile URL, do not refer to the user provided URL as such
Editorial changes to use the term "host" instead of "domain" where appropriate
C.4
Changes from 09 August 2020 to 26 September 2020
Make the
me
parameter optional (but recommended) in the authorization request
Add the option of returning profile information in the response as well as defining profile scopes
Incorporate PKCE into the spec
Fixed text about which URL to resolve relative authorization/token endpoint URLs from
C.5
Changes from 25 January 2020 to 09 August 2020
Use
response_type=code
and make it required, to bring it in line with OAuth 2.0
Require
grant_type=authorization_code
when redeeming the authorization code at the authorization endpoint
Drop the
me
parameter from the token endpoint request
Consolidate the authentication and authorization sections into a single section, describing only the difference which is the response returned.
Drop the section describing communication between token endpoints and authorization endpoints as it was underused
Editorial changes and rearranging sections
C.6
Changes from 03 March 2019 to 25 January 2020
Use "authentication" and "authorization" more consistently in paragraphs and diagrams
Clarify that "Authorization Code Flow" is "OAuth 2.0 Authorization Code Flow"
Minor typo fixes
C.7
Changes from 07 July 2018 to 03 March 2019
Updates the spec header to note that it is a living standard
Minor typo fixes
C.8
Changes from
23 January 2018
to 07 July 2018
Replaced references to RFC 5988 with RFC 8288 (
diff
Added
Accept: application/json
header to example requests (
diff
C.9
Changes from 07 July 2018 to 03 March 2019
Added missing ampersand in HTTP redirect example (
diff
Fixed broken references section (
diff
Fixed internal link to redirect examples (
diff
D.
References
D.1
Normative references
[ClientIDMetadataDocument]
OAuth Client ID Metadata Document
. Aaron Parecki; Emelia Smith. IETF. Internet-Draft. URL:
[ClientMetadata]
OAuth Dynamic Client Registration Metadata
. IETF. IANA. Registry. URL:
[Fetch]
Fetch Standard
. Anne van Kesteren. WHATWG. Living Standard. URL:
[HTML]
HTML Standard
. Anne van Kesteren; Domenic Denicola; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. Living Standard. URL:
[RFC2119]
Key words for use in RFCs to Indicate Requirement Levels
. S. Bradner. IETF. March 1997. Best Current Practice. URL:
[RFC5735]
Special Use IPv4 Addresses
. M. Cotton; L. Vegoda. IETF. January 2010. Best Current Practice. URL:
[RFC6749]
The OAuth 2.0 Authorization Framework
. D. Hardt, Ed.. IETF. October 2012. Proposed Standard. URL:
[RFC6750]
The OAuth 2.0 Authorization Framework: Bearer Token Usage
. M. Jones; D. Hardt. IETF. October 2012. Proposed Standard. URL:
[RFC7009]
OAuth 2.0 Token Revocation
. T. Lodderstedt, Ed.; S. Dronia; M. Scurtescu. IETF. August 2013. Proposed Standard. URL:
[RFC7159]
The JavaScript Object Notation (JSON) Data Interchange Format
. T. Bray, Ed.. IETF. March 2014. Proposed Standard. URL:
[RFC7231]
Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content
. R. Fielding, Ed.; J. Reschke, Ed.. IETF. June 2014. Proposed Standard. URL:
[RFC7591]
OAuth 2.0 Dynamic Client Registration Protocol
. J. Richer, Ed.; M. Jones; J. Bradley; M. Machulak; P. Hunt. IETF. July 2015. Proposed Standard. URL:
[RFC7636]
Proof Key for Code Exchange by OAuth Public Clients
. N. Sakimura, Ed.; J. Bradley; N. Agarwal. IETF. September 2015. Proposed Standard. URL:
[RFC7662]
OAuth 2.0 Token Introspection
. J. Richer, Ed.. IETF. October 2015. Proposed Standard. URL:
[RFC8288]
Web Linking
. M. Nottingham. IETF. October 2017. Proposed Standard. URL:
[RFC8414]
OAuth 2.0 Authorization Server Metadata
. M. Jones; N. Sakimura; J. Bradley. IETF. June 2018. Proposed Standard. URL:
[RFC9207]
OAuth 2.0 Authorization Server Issuer Identification
. K. Meyer zu Selhausen; D. Fett. IETF. March 2022. Proposed Standard. URL:
[URL]
URL Standard
. Anne van Kesteren. WHATWG. Living Standard. URL:
D.2
Informative references
[Micropub]
Micropub
. Aaron Parecki. W3C. 23 May 2017. W3C Recommendation. URL:
[RelMeAuth]
RelMeAuth
. Tantek Çelik. microformats.org. Living Specification. URL:
[RFC6819]
OAuth 2.0 Threat Model and Security Considerations
. T. Lodderstedt, Ed.; M. McGloin; P. Hunt. IETF. January 2013. Informational. URL: