-
Notifications
You must be signed in to change notification settings - Fork 385
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- makes some metadata optional - better explain how each metadata field is used - better explain what the restrictions on redirect_uris are - remove the signed metadata part - mention the client metadata JSON document alternative
- Loading branch information
Showing
1 changed file
with
185 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,99 +1,231 @@ | ||
# MSC2966: Usage of OAuth 2.0 Dynamic Client Registration in Matrix | ||
|
||
[MSC2964](https://github.com/matrix-org/matrix-doc/pull/2964) defines how client should login against a Matrix server using OAuth 2.0. | ||
It assumes the client is known to the authentication server. | ||
This proposal is part of the broader [MSC3861: Next-generation auth for Matrix, based on OAuth 2.0/OIDC](https://github.com/matrix-org/matrix-spec-proposals/pull/3861). | ||
|
||
This MSC specifies how Matrix clients should leverage OAuth 2.0 Dynamic Client Registration Protocol ([RFC 7591](https://tools.ietf.org/html/rfc7591)) to register themselves before initiating the login flow. | ||
This MSC specifies how Matrix clients should leverage the OAuth 2.0 Dynamic Client Registration Protocol ([RFC 7591](https://tools.ietf.org/html/rfc7591)) to register themselves before initiating an authorization flow. | ||
|
||
## Proposal | ||
|
||
If a Matrix server wants to be used by any third-party client, its authentication server must allow dynamic registration of OAuth 2.0 clients. | ||
The client registration endpoint is advertised in the OIDC discovery document and can be used as per [RFC 7591 sec. 3](https://tools.ietf.org/html/rfc7591#section-3). | ||
### Prerequisites | ||
|
||
This proposal requires the client to know the following authorization server metadata about the homeserver: | ||
|
||
- `registration_endpoint`: the URL where the user is able to access the client registration endpoint. | ||
|
||
The discovery of the above metadata is out of scope for this MSC and is currently covered by [MSC2965](https://github.com/matrix-org/matrix-doc/pull/2965). | ||
|
||
### Client metadata | ||
|
||
When registering itself, a client must provide a list of metadata about itself. | ||
In OAuth 2.0, clients have a set of metadata values associated with their client identifier at an authorization server. | ||
These values are used to describe the client to the user and define how the client interacts with the authorization server. | ||
|
||
This MSC specifies what metadata values are required by the Matrix specification and how a client can register itself with a Matrix homeserver to get a client identifier. | ||
|
||
The metadata names are registered in the IANA [OAuth Dynamic Client Registration Metadata](https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml#client-metadata) registry, and normative definitions of them are available in their respective RFCs in the registry. | ||
|
||
#### Localizable metadata | ||
|
||
#### `client_uri` and relationship with other URIs | ||
|
||
The `client_uri` metadata is required to be a valid URI. | ||
This URI must use the `https` scheme. | ||
|
||
The host part of the URI must be a public hostname that is not a [public suffix](https://publicsuffix.org). | ||
IP addresses and private hostnames like `localhost` are not allowed. | ||
|
||
It is recommended that the `client_uri` is a web page that provides information about the client. | ||
This page should be able to be accessed without requiring authentication. | ||
|
||
This URI is a common base for all the other URIs in the metadata: those must be either on the same host or on a subdomain of the host of the `client_uri`. | ||
For example, if the `client_uri` is `https://example.com/`, then one of the `redirect_uris` can be `https://example.com/callback` or `https://app.example.com/callback`, but not `https://app.com/callback`. | ||
|
||
#### User-visible metadata values | ||
|
||
The following metadata values should be used by clients to help users identify the client: | ||
|
||
As per [RFC 7591 sec. 2.2](https://tools.ietf.org/html/rfc7591#section-2.2), some of those metadata values may be localized. | ||
- `client_name`: Human-readable name of the client to be presented to the user | ||
- `logo_uri`: URL that references a logo for the client | ||
- `tos_uri`: URL that points to a human-readable terms of service document for the client | ||
- `policy_uri`: URL that points to a human-readable policy document for the client | ||
|
||
All the URIs must use the `https` scheme and use the `client_uri` as a common base. | ||
|
||
All of these metadata values are optional. | ||
|
||
As per [RFC 7591 sec. 2.2](https://tools.ietf.org/html/rfc7591#section-2.2), these metadata values may be localized. | ||
For example: | ||
|
||
```json | ||
{ | ||
"client_name": "Digital mailbox", | ||
"client_name#en-US": "Digital mailbox", | ||
"client_name#en-GB": "Digital postbox", | ||
"client_name#fr": "Boîte aux lettres numérique" | ||
"client_name#fr": "Boîte aux lettres numérique", | ||
"tos_uri": "https://example.com/tos.html", | ||
"tos_uri#fr": "https://example.com/fr/tos.html", | ||
"policy_uri": "https://example.com/policy.html", | ||
"policy_uri#fr": "https://example.com/fr/policy.html" | ||
} | ||
``` | ||
|
||
Some of those metadatas are optional in the RFC but required in this context. | ||
#### Metadata values required by the OAuth 2.0 authorization grant flow | ||
|
||
| Name | Description | Behaviour | Localizable | | ||
| ---------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ----------- | | ||
| `client_name` | Human-readable name of the client to be presented to the user | Required | Yes | | ||
| `client_uri` | URL of a web page providing information about the client | Required | Yes | | ||
| `logo_uri` | URL that references a logo for the client | Optional | Yes | | ||
| `contacts` | Array of strings representing ways to contact people responsible for this client, typically email addresses | Required, non-empty | No | | ||
| `tos_uri` | URL that points to a human-readable terms of service document for the client | Required | Yes | | ||
| `policy_uri` | URL that points to a human-readable policy document for the client | Required | Yes | | ||
| `redirect_uris` | Array of redirection URIs for use in redirect-based flows | Required with the `authorization_code` grant ype | No | | ||
| `response_types` | Array of the OAuth 2.0 response types that the client may use | Defaults to `["code"]` | No | | ||
| `grant_types` | Array of OAuth 2.0 grant types that the client may use | Defaults to `["authorization_code"]` | No | | ||
The following metadata values are required to be present to use the OAuth 2.0 authorization code grant, as described in [MSC2964]: | ||
|
||
Other metadata registered in the IANA [OAuth Dynamic Client Registration Metadata](https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml#client-metadata) registry might be used and supported by Matrix servers and clients. | ||
- `redirect_uris`: Array of redirection URIs for use in redirect-based flows | ||
- `response_types`: Array of the OAuth 2.0 response types that the client may use | ||
- `grant_types`: Array of OAuth 2.0 grant types that the client may use | ||
|
||
### User consent | ||
To use this grant, along with refresh tokens: | ||
|
||
When authorizing a third-party client for the first time, the authorization server must ask for explicit user consent and display as much information, preferably localized, about the client as possible. | ||
This includes informations about the publisher, the clients terms of service and its policy. | ||
- the `redirect_uris` must have at least one value | ||
- the `response_types` must include `code` | ||
- the `grant_types` must include `authorization_code` and `refresh_token` | ||
|
||
The consent screen must include a human-readable list of the scopes requested by the client. | ||
#### Redirect URI validation | ||
|
||
### Metadata signature | ||
The redirect URI plays a critical role in validating the authenticity of the client. | ||
The client 'proves' its identity by demonstrating that it controls the redirect URI. | ||
This is why it is critical to have strict validation of the redirect URI. | ||
|
||
To securely identify themselves, clients must send a digitally signed version of their metadata. | ||
This is done by encoding the client metadata in a JWT and signing it. | ||
The `application_type` metadata is used to determine the type of client. | ||
It defaults to `web` if not present, and can be set to `native` to indicate that the client is a native application. | ||
|
||
In addition the client metadata mentioned earlier, the JWT payload must include the following: | ||
In all cases, the redirect URI must not have a fragment component. | ||
|
||
- `iss`: the entity signing the token. This must allow the authorization server to discover the JWT keys of the issuer. | ||
- `iat`: the timestamp when the JWT was signed | ||
- `exp`: a timestamp after which the JWT isn't valid anymore | ||
- `software_id`: a random string uniquely identifying this instance. A random UUIDv4 is suggested for this field | ||
#### Web clients | ||
|
||
This allows client to securely update their metadata without being considered as a new client and re-asking user consent. | ||
`web` clients can use redirect URIs that: | ||
|
||
The `software_id` is used to uniquely identify a client and ensure the same `client_id` is returned on subsequent registration. | ||
Each `software_id` is tied to the issuer (`iss`) and therefore subsequent registration must be signed by the same issuer. | ||
- must use the `https` scheme | ||
- must omit the port (to use the default port for https: 443) | ||
- must not use a user or password in the authority component of the URI | ||
- must use the client URI as a common base for the authority component | ||
|
||
The issuer keys can be retrieved using its [OIDC discovery document](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata) (`<iss>/.well-known/openid-configuration`) or its [authorization server metadata](https://tools.ietf.org/html/rfc8414) (`<iss>/.well-known/oauth-authorization-server`). | ||
The issuer does not have to be an actual authorization server, but its metadata can include human-readable informations about the issuer. | ||
Those informations can be displayed on the user consent screen to tell the user about the client's publisher. | ||
Examples of valid redirect URIs (with `https://example.com/` as the client URI): | ||
|
||
The JWT payload may also include a `software_version` claim denoting the version of the client being registered. | ||
This field should be treated as an opaque string by the authorization server. | ||
- `https://example.com/callback` | ||
- `https://app.example.com/callback` | ||
- `https://example.com/?query=value` | ||
|
||
A Matrix server may choose to only allow signed client to be registered. | ||
It might also have an list of trusted issuers for software statements and only allow those to restrict third-party clients. | ||
Examples of invalid redirect URIs (with `https://example.com/` as the client URI): | ||
|
||
## Potential issues | ||
- `https://example.com/callback#fragment` | ||
- `https://example.com:8080/callback` | ||
- `http://example.com/callback` | ||
- `http://localhost/` | ||
|
||
#### Native clients | ||
|
||
`native` clients can use three types of redirect URIs: | ||
|
||
1. Private-Use URI Scheme: | ||
- the scheme must be prefixed with the client URI hostname in reverse-DNS notation. For example, if the client URI is `https://example.com/`, then a valid custom URI scheme would be `com.example.app:/`. | ||
- the URI must not have an authority component. This means it should have a single slash after the scheme, with no hostname, username, or port. | ||
2. "http" URIs on the loopback interface: | ||
- it must use the `http` scheme | ||
- the host part must be `localhost`, `127.0.0.1`, or `[::1]` | ||
- it must have no port registered. The homeserver will then accept any port number during the authorization flow. | ||
3. Claimed "https" Scheme URI: | ||
- some operating systems allow apps to claim "https" scheme URIs in the domains they control | ||
- when the browser encounters a claimed URI, instead of the page being loaded in the browser, the native app is launched with the URI supplied as a launch parameter | ||
- the same rules as for `web` clients apply | ||
|
||
These restrictions are the same as defined by [RFC8252 sec. 7](https://tools.ietf.org/html/rfc8252#section-7). | ||
|
||
Examples of valid redirect URIs (with `https://example.com/` as the client URI): | ||
|
||
- `com.example.app:/callback` | ||
- `com.example:/` | ||
- `http://localhost/callback` | ||
- `http://127.0.0.1/callback` | ||
- `http://[::1]/callback` | ||
|
||
Examples of invalid redirect URIs (with `https://example.com/` as the client URI): | ||
|
||
- `example:/callback` | ||
- `com.example.com://callback` | ||
- `https://localhost/callback` | ||
- `http://localhost:1234/callback` | ||
|
||
It is unclear how metadata updates should be handled. | ||
If a client changes its `redirect_uris`, should the old ones be considered for a period of time? | ||
If multiple versions of the same client coexist at the same time, should older versions of the software be able to override the metadata of the newer version? | ||
### Dynamic client registration | ||
|
||
If an authorization server allows unsigned clients, the number of client registration might explode exponentially. | ||
At the same time, only allowing signed clients can make client development significantly harder. | ||
Before initiating an authorization flow, the client must advertise its metadata to the homeserver to get back a `client_id`. | ||
|
||
This is done through the `registration_endpoint` as described by [RFC7591 sec. 3](https://tools.ietf.org/html/rfc7591#section-3). | ||
|
||
To register, the client sends an HTTP POST to the `registration_endpoint` with its metadata as JSON in the body. | ||
For example, the client could send the following registration request: | ||
|
||
```http | ||
POST /register HTTP/1.1 | ||
Content-Type: application/json | ||
Accept: application/json | ||
Server: auth.example.com | ||
``` | ||
|
||
```json | ||
{ | ||
"client_name": "My App", | ||
"client_name#fr": "Mon application", | ||
"client_uri": "https://example.com/", | ||
"logo_uri": "https://example.com/logo.png", | ||
"tos_uri": "https://example.com/tos.html", | ||
"tos_uri#fr": "https://example.com/fr/tos.html", | ||
"policy_uri": "https://example.com/policy.html", | ||
"policy_uri#fr": "https://example.com/fr/policy.html", | ||
"redirect_uris": ["https://app.example.com/callback"], | ||
"response_types": ["code"], | ||
"grant_types": ["authorization_code", "refresh_token"], | ||
"application_type": "web" | ||
} | ||
``` | ||
|
||
The server replies with a JSON object containing the `client_id` allocated, as well as all the metadata values that the server registered. | ||
|
||
With the previous registration request, the server would reply with: | ||
|
||
```json | ||
{ | ||
"client_id": "s6BhdRkqt3", | ||
"client_name": "My App", | ||
|
||
|
||
"client_uri": "https://example.com/", | ||
"logo_uri": "https://example.com/logo.png", | ||
"tos_uri": "https://example.com/tos.html", | ||
"policy_uri": "https://example.com/policy.html", | ||
"redirect_uris": ["https://app.example.com/callback"], | ||
"response_types": ["code"], | ||
"grant_types": ["authorization_code", "refresh_token"], | ||
"application_type": "web" | ||
} | ||
``` | ||
|
||
**Note**: in this example, the server has not registered the locale-specific values for `client_name`, `tos_uri`, and `policy_uri`, which is why they are not present in the response. | ||
|
||
The client must store the `client_id` for future use. | ||
|
||
## Potential issues | ||
|
||
Because each client on each user device will do its own registration, they will all have different `client_id`s. | ||
This means that the number of client registrations will grow exponentially. | ||
A subsequent MSC could be proposed to identify multiple instances of the same client using signed client metadata. | ||
|
||
## Alternatives | ||
|
||
None relevant. | ||
An alternative approach would be to have the client host a JSON file containing its metadata and use that URL as the `client_id`. | ||
This is what the following [*OAuth Client ID Metadata Document* draft](https://datatracker.ietf.org/doc/html/draft-parecki-oauth-client-id-metadata-document) proposes. | ||
|
||
This approach has the advantage of being able to use the same `client_id` for different instances of the same client, but it has the disadvantage of requiring the client to host a JSON file on its own domain, as well as difficulties in handling updates to the metadata. | ||
|
||
## Security considerations | ||
|
||
Nothing prevents intentional collisions in `software_id`. | ||
An attacker could register a `software_id` of another client before its first registration, blocking it from registration. | ||
The registration endpoint should be rate-limited and the failed registration monitored by server administrators to detect such abuses. | ||
TBD | ||
|
||
## Unstable prefix | ||
|
||
None relevant. | ||
|
||
[RFC7591]: https://tools.ietf.org/html/rfc7591 | ||
[MSC2964]: https://github.com/matrix-org/matrix-spec-proposals/pull/2964 |