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.
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
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 Authorization Endpoint is responsible for obtaining authentication or authorization consent from the end user and generating and verifying authorization codes.
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.
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 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
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.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.
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.
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 screenclient_uri
- URL of a webpage providing information about the clientlogo_uri
- (optional) URL that references a logo or icon for the clientredirect_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.
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 <link>
tags or Link
HTTP headers with a rel
attribute of redirect_uri
at the client_id
URL to be used by the authorization server.
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>
This section describes how to authenticate users and optionally obtain an access token using the OAuth 2.0 Authorization Code Flow with IndieAuth.
rel=indieauth-metadata
valueauthorization_endpoint
and token_endpoint
valuesNote: 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.
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 .
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"] }
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 responseclient_id
- The client URLredirect_uri
- The redirect URL indicating where the user should be redirected to after approving the requeststate
- 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 enteredhttps://example.org/auth?response_type=code& 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.
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.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:
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.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.
Once the client has obtained an authorization code, it can redeem it for an access token or the user's final profile URL.
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.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=a6128783714cfda1d388e2e98b6ae8221ac31aca31959e59512c59f5Example request to token endpoint
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
.
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.
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.
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:
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.
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:
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.
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.
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.
The basic redirect example covers cases such as:
Steps
www.example.com
into the clienthttp://www.example.com/
http://www.example.com/
https://example.com/
https://example.com/
and finds the authorization endpointme
value of https://example.com/
as the canonical Profile URL.https://example.com/
example.com
into the clienthttp://example.com/
http://example.com/
https://example.com/
https://example.com/
and finds the authorization endpoint, https://login.example.com
https://login.example.com
. This results in the profile URL response with a me
value of https://username.example.com/
as the canonical Profile URL.https://username.example.com/
and finds the same authorization endpoint https://login.example.com
me
value of https://username.example.com/
example.com
into the clienthttp://example.com/
http://example.com/
https://example.com/
https://example.com/
and finds the authorization endpoint, https://login.example.com
https://login.example.com
. This results in the profile URL response with a me
value of https://example.com/username
as the canonical Profile URL.https://example.com/username
and finds the same authorization endpoint https://login.example.com
me
value of https://example.com/username
user@example.com
into the clienthttp://user@example.com/
http://example.com/
providing the HTTP Basic Auth username user
https://example.com/
https://example.com/
and finds the authorization endpoint, https://login.example.com
http://user@example.com/
request directly instead of needing a separate redirecthttps://login.example.com
, 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 https://example.com/username
as the canonical Profile URL.https://example.com/username
and finds the same authorization endpoint https://login.example.com
me
value of https://example.com/username
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 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.
The link relation types below are documented to be registered by IANA per Section 6.2.1 of [[!RFC8288]]:
You can find a list of articles about IndieAuth on the IndieWeb wiki.
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, Emelia Smith, Fluffy, François Kooman, Jamie Tanna, Jeena Paradies, Manton Reece, Martijn van der Ven, Sebastiaan Andeweg, Sven Knebel, and Tantek Çelik.
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