-
Notifications
You must be signed in to change notification settings - Fork 411
MSC4363: OAuth step up authentication #4363
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Johennes
wants to merge
8
commits into
matrix-org:main
Choose a base branch
from
Johennes:johannes/oauth-step-up-authentication
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
fd17d14
MSC4363: OAuth step up authentication
Johennes 4c716b6
Add WWW-Authenticate and insufficient_scope alternatives
Johennes d48b01d
Clarify which scopes to use when the challenge doesn't include any
Johennes bbae0bb
Don't distinguish homeservers and authorization servers
Johennes 8cdb9b6
Reify semantics of token issuance and use
Johennes 4bf1cf0
Fix typos
Johennes e4c0b02
authentication -> authorization
Johennes 5104f18
Renewing -> Refreshing
Johennes File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 |
---|---|---|
@@ -0,0 +1,147 @@ | ||
# MSC4363: OAuth step up authentication | ||
|
||
Homeservers may want to enforce re-authentication to guard access to potentially severe user actions | ||
such as deactivating an account or logging out all devices. Prior to the [OAuth APIs] introduced in | ||
Matrix 1.15, this was handled by an API called [User-Interactive Authentication (UIA)]. UIA is | ||
incompatible with the new [OAuth APIs], however, leading to suboptimal workarounds such as | ||
[MSC4312]. | ||
|
||
Fortunately, OAuth itself provides a scheme for elevating access rights with [RFC9470] (OAuth 2.0 | ||
Step Up Authentication Challenge Protocol). The present proposal generalizes [RFC9470] for use with | ||
Matrix. | ||
|
||
## Proposal | ||
|
||
The following description assumes that the client has authenticated via the [OAuth APIs]. | ||
|
||
When a homeserver determines that the authentication event associated with the access token | ||
presented on a request is insufficient, it MAY respond with HTTP 401 and a new error code | ||
`M_INSUFFICIENT_USER_AUTHENTICATION`. Three optional top-level properties are allowed in the | ||
response to convey the authentication requirements challenge back to the client: | ||
|
||
- `acr_values`: A space-separated string listing the authentication context class reference (ACR) | ||
values in order of preference.[^1] The protected resource requires *one* of these values for the | ||
authentication event associated with the access token. | ||
- `max_age`: A non-negative integer specifying the allowable elapsed time in seconds since the last | ||
active authentication event associated with the access token. | ||
- `scope`: A space-separated string listing the *full* set of scopes that are required to access the | ||
protected resource. | ||
|
||
The following is an example of an error response that requests authentication using either any 2FA | ||
method, or, failing that, password-based authentication. Additionally, a maximum elapsed time since | ||
authentication of 5 minutes is required. The ACR values were taken from [Okta's reference]. | ||
|
||
``` json5 | ||
{ | ||
"errcode": "M_INSUFFICIENT_USER_AUTHENTICATION", | ||
"error": "Additional authentication required to complete request", | ||
"acr_values": "urn:okta:loa:2fa:any urn:okta:loa:1fa:pwd", | ||
"max_age": 300 | ||
} | ||
``` | ||
|
||
A client receiving a challenge SHOULD use the `acr_values`, `max_age` and `scope` properties to | ||
construct a new authorization request. For this purpose, `acr_values` and `max_age` are added to the | ||
[current list of request parameters] using the same definition given above. If the challenge doesn't | ||
include any scopes, the client SHOULD use the same scopes it used during login on the authorization | ||
request. | ||
|
||
Following successful authorization, the client's previous access token SHOULD be invalidated and a | ||
new, more privileged, token be issued. The new token SHOULD have a short lifetime. The client can | ||
then use the new token to repeat the original request but may also use it for other API requests. | ||
Refreshing the token SHOULD produce a less privileged token again. This approach ensures that | ||
implementations can continue to maintain only a single access token per device as they do today. | ||
|
||
### Aspects that are out of scope | ||
|
||
This proposal consciously leaves a number of things undefined. | ||
|
||
Firstly, the act of evaluating whether or not an access token meets a resource's requirements is | ||
left as an implementation detail of the homeserver. As per [RFC9470], this can, for instance, be | ||
achieved by encoding the access token with additional properties in JWT format. Alternatively, if | ||
the homeserver delegates authorization to an external authorization server, a dedicated token | ||
introspection endpoint could be used. | ||
|
||
Furthermore, no concrete ACR values are specified. Again, this is an implementation detail of the | ||
homeserver as ACR values are not intended for introspection by clients. | ||
|
||
Finally, it is left up to the homeserver to determine how exactly the `acr_values`, `max_age` and | ||
`scope` parameters are used during authentication. Implementations should, however, note the | ||
recommendations in [RFC9470]. | ||
|
||
## Potential issues | ||
|
||
None apparent. | ||
|
||
## Alternatives | ||
Johennes marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Rather than extending the existing [standard error response], the error and parameters could be | ||
communicated via the `WWW-Authenticate` header as suggested in [RFC9470]. Reusing the example from | ||
above, the header would look like this: | ||
|
||
``` http | ||
HTTP/1.1 401 Unauthorized | ||
WWW-Authenticate: Bearer error="insufficient_user_authentication", | ||
error_description="Additional authentication required to complete request", | ||
acr_values="urn:okta:loa:2fa:any urn:okta:loa:1fa:pwd", | ||
max_age="300" | ||
``` | ||
|
||
Switching to the header would break with the established error mechanism in Matrix, however. As a | ||
middleground, the header could also be used *on* standard error responses. It's unclear though what | ||
advantages it would bring to have two different mechanisms that convey the same information. | ||
|
||
Rather than replacing the current access token, a new token could be issued without invalidating the | ||
existing one. The client would then use the new token only for repeating the original request and | ||
continue using the old token for all other requests. This enables one-shot tokens but would mean | ||
that implementations have to start managing more than one token per device. Moreover, homeservers | ||
could also achieve one-shot-like semantics by re-applying this proposal's step-up process to the new | ||
token. | ||
|
||
A [previous version] of [MSC2967] used the `insufficient_scope` error code from [RFC6750] (The OAuth | ||
2.0 Authorization Framework: Bearer Token Usage) to communicate missing scopes back to the client. | ||
This is comparable to but less flexible than the present proposal as it lacks ACRs and token age. | ||
|
||
Finally, the scheme proposed in [MSC4312] (ab)uses UIA to deeplink into the homeserver's account | ||
management web UI. This is less flexible and powerful than OAuth step up authentication, however. It | ||
is also contrary to the idea of standardizing authentication in Matrix on OAuth mechanisms. | ||
|
||
## Security considerations | ||
|
||
The security impact of this proposal largely follows [RFC9470]. | ||
|
||
Depending on the concrete values used in the `acr_values` parameter, it is possible to leak | ||
information about the authenticated user, the protected resource, the authorization server, and any | ||
other context-specific data. This risk can be controlled by implementations deciding on the values. | ||
|
||
To prevent leaking required properties of an authorization token to an actor who has not proven they | ||
can obtain a token, homeservers SHOULD NOT return a challenge without verifying the client presented | ||
a valid token. | ||
|
||
## Unstable prefix | ||
|
||
While this MSC is not considered stable, the following replacements should be used in the | ||
homeserver's error response: | ||
|
||
- `M_INSUFFICIENT_USER_AUTHENTICATION` → `org.matrix.msc4363.M_INSUFFICIENT_USER_AUTHENTICATION` | ||
- `acr_values` → `org.matrix.msc4363.acr_values` | ||
- `max_age` → `org.matrix.msc4363.max_age` | ||
- `scope` → `org.matrix.msc4363.scope` | ||
|
||
The new authorization request parameters should not use prefixes since they follow standard OAuth. | ||
|
||
[^1]: As defined in the [OIDC core specification], the authentication context conveys information | ||
about how authentication takes place (e.g., what authentication method(s) or assurance level to | ||
meet). | ||
|
||
[OAuth APIs]: https://spec.matrix.org/v1.15/client-server-api/#oauth-20-api | ||
[User-Interactive Authentication (UIA)]: https://spec.matrix.org/v1.16/client-server-api/#user-interactive-authentication-api | ||
[MSC4312]: https://github.com/matrix-org/matrix-spec-proposals/pull/4312 | ||
[RFC9470]: https://datatracker.ietf.org/doc/rfc9470/ | ||
[Okta's reference]: https://developer.okta.com/docs/guides/step-up-authentication/main/ | ||
[current list of request parameters]: https://spec.matrix.org/v1.15/client-server-api/#login-flow | ||
[standard error response]: https://spec.matrix.org/v1.16/client-server-api/#standard-error-response | ||
[previous version]: https://github.com/matrix-org/matrix-spec-proposals/pull/2967/commits/544d75b413277f14393a635ea17be3d0d49529c5 | ||
[MSC2967]: github.com/matrix-org/matrix-doc/pull/2967 | ||
[RFC6750]: https://datatracker.ietf.org/doc/html/rfc6750 | ||
[OIDC core specification]: https://openid.net/specs/openid-connect-core-1_0.html#Terminology |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implementation requirements: