diff --git a/proposals/2967-api-scopes.md b/proposals/2967-api-scopes.md new file mode 100644 index 00000000000..78d22a48b37 --- /dev/null +++ b/proposals/2967-api-scopes.md @@ -0,0 +1,138 @@ +# MSC2967: API scopes + +This proposal is part of the broader [MSC3861: Next-generation auth for Matrix, based on OAuth 2.0/OIDC][MSC3861]. + +When a user signs in with a Matrix client, it currently gives the client full access to their Matrix account. + +This proposal introduces access scopes to allow restricting client access to only part(s) of the Matrix client API. + +## Proposal + +[MSC2964] introduces the usage of the OAuth 2.0 authorization code grant to authenticate against a Matrix homeserver. + +An OAuth 2.0 grant has a scope associated to it which provides a framework for obtaining user consent. + +The framework encourages the practise of obtaining additional use consent when a client asks for a new scope that was not granted previously. + +This MSC does not attempt to define all the scopes necessary to cover all Matrix APIs and use cases, but proposes the structure of a namespace and a few scopes to cover existing use cases. + +### Scope format + +All scopes related to Matrix should start with `urn:matrix:` and use the `:` delimiter for further sub-division. + +Scopes related to mapping of Client-Server API access levels should start with `urn:matrix:client:`. + +For future MSCs that build on this namespace, unstable subdivisions should be used whilst in development. + +For example, if MSCXXXX wants to introduce the `urn:matrix:client:foo` scope, it could use `urn:matrix:client:com.example.mscXXXX.foo` during development. +If it needs to introduce multiple scopes, like `urn:matrix:client:foo` and `urn:matrix:client:bar`, it could use `urn:matrix:client:com.example.mscXXXX:foo` and `urn:matrix:client:com.example.mscXXXX:bar`. + +### Allocated scopes + +#### Full API read/write access + +To support the existing semantic of granting full access to the Matrix C-S API the following scope is assigned: + +| Scope | Purpose | +| - | - | +| `urn:matrix:client:api:*` | Grants full access to the Client-Server API | + +In the future, a client would request more specific actions when required. e.g. something like `urn:matrix:client:api:read:*` + +#### Device ID handling + +Presently a device ID is typically generated by the homeserver and is associated with a specific series of access tokens. + +This MSC proposes that the Matrix client is responsible for generating/allocating a device ID. +A client can create a new device ID by generating a random string and asking for its associated scope on login. +A client can adopt and rehydrate an existing device ID by asking for its associated scope on login. + +The client must then add the requested device ID to the grant by including following token in the requested scope: +`urn:matrix:client:device:`, where `` is the requested device ID. + +There MUST be exactly one `urn:matrix:client:device:` token in the requested scope. + +When generating a new device ID, the client SHOULD generate a random string with enough entropy. +It SHOULD only use characters from the unreserved character list defined by [RFC3986]: + +> unreserved = a-z / A-Z / 0-9 / "-" / "." / "_" / "~" + +Using this alphabet, a 10 character string is enough to stand a sufficient chance of being unique per user. +The homeserver MAY reject a request for a device ID that is not long enough or contains characters outside the unreserved list. + +In any case it MUST only use characters allowed by the OAuth 2.0 scope definition in [RFC6749] section 3.3, +which is defined as the following ASCII ranges: `%x21 / %x23-5B / %x5D-7E`, i.e: + + - alphanumeric characters (`A-Z`, `a-z`, `0-9`) + - the following characters: `! # $ % & ' ( ) * + , - . / : ; < = > ? @ [ ] ^ _ \` { | } ~` + +### Future scopes + +Exact scopes for the whole API are intentionally not specified in this MSC. + +It is envisioned that the namespace could be further partitioned to support use cases such as read only, write only, limited to one or more rooms etc. + +Some thoughts/ideas for possible scopes are: + +- `urn:matrix:client:api:` or `urn:matrix:client:api::*` - grant limited access to the client API in all rooms. Permissions could be read, write, delete, append. +- `urn:matrix:client:api:read:` - read-only access to the client API for just the named resource. e.g. `urn:matrix:client:api:read:#matrix-auth` + +New MSCs should be created for proposing and discussing such new scopes. + +## Potential issues + +### Device ID collision + +The Device ID handling involves a change in where device IDs are generated. +Because the device ID is now generated by the client, it is possible to have a device ID collision. + +Requiring enough entropy on the device ID ensures that the device ID is unique. +With a 66 character alphabet and a 10 character device ID, the probability of a collision between 100 million devices is around 0.3%: + +$$N = 66^{10}$$ +$$K = 10^{8}$$ +$$P \approx 1 - e^{-\frac{K^2}{2N}}$$ +$$P \approx 0.00318$$ + +This does also restrict the possible alphabet of device IDs, which was not restricted before. + +### Generating the device ID on the client + +This proposal effectively changes where the device ID is generated, from "most of the time on the server" to "every time on the client." + +This doesn't introduce a new mechanism, as clients could already select a device ID instead of letting the server generate one. + +One of the original motivation for this change was to adopt existing OAuth 2.0 mechanisms as much as possible. +This meant not introducing Matrix-specific parameters (hence encoding the device ID in the scope) and not relying on non-standard server behaviour (hence the device ID being generated on the client). + +In retrospect, because the whole proposal requires a Matrix-specific implementation anyway, compatibility with existing off-the-shelf OAuth 2.0 server implementations isn't a goal anymore: +we could adopt a Matrix-specific parameter to specify the device ID, and let the server generate it if it's not provided. + +As generating the device ID on the client hasn't been a problem in practice, this proposal kept it like that to avoid the cost of aligning the implementations. + +## Alternatives + +### Scopes + +Scope could also have an URL format, e.g. `https://matrix.org/api/*/read`. + +The URL prefix could either be static (`https://matrix.org`) or dependant on the homeserver (`https://matrix.example.com`). +In both cases, the URL could be confused with API endpoints and in the second case it would require discovery to know what scopes to ask. + +The actual namespace prefix and subdivisions are open to debate. + +## Security considerations + +As we are just representing existing access models there shouldn't be anything special. + +## Unstable prefix + +While this feature is in development the following unstable scope prefixes should be used: + +- `urn:matrix:client` --> `urn:matrix:org.matrix.msc2967.client` + +[MSC1597]: https://github.com/matrix-org/matrix-spec-proposals/pull/1597 +[MSC2964]: https://github.com/matrix-org/matrix-spec-proposals/pull/2964 +[MSC3861]: https://github.com/matrix-org/matrix-spec-proposals/pull/3861 +[RFC3986]: https://datatracker.ietf.org/doc/html/rfc3986 +[RFC6749]: https://datatracker.ietf.org/doc/html/rfc6749