Fleshed out login spec.
This commit is contained in:
parent
7acede1e42
commit
52cfdfd5f1
|
@ -201,124 +201,133 @@ Clients must register with a home server in order to use Matrix. After
|
||||||
registering, the client will be given an access token which must be used in ALL
|
registering, the client will be given an access token which must be used in ALL
|
||||||
requests to that home server as a query parameter 'access_token'.
|
requests to that home server as a query parameter 'access_token'.
|
||||||
|
|
||||||
- TODO Kegan : Make registration like login
|
- TODO Kegan : Make registration like login (just omit the "user" key on the
|
||||||
|
initial request?)
|
||||||
- TODO Kegan : Allow alternative forms of login (>1 route)
|
- TODO Kegan : Allow alternative forms of login (>1 route)
|
||||||
|
|
||||||
If the client has already registered, they need to be able to login to their
|
If the client has already registered, they need to be able to login to their
|
||||||
account. The home server may provide many different ways of logging in, such
|
account. The home server may provide many different ways of logging in, such
|
||||||
as user/password auth, login via a social network (OAuth), login by confirming
|
as user/password auth, login via a social network (OAuth2), login by confirming
|
||||||
a token sent to their email address, etc. This specification does not define how
|
a token sent to their email address, etc. This specification does not define how
|
||||||
home servers should authorise their users who want to login to their existing
|
home servers should authorise their users who want to login to their existing
|
||||||
accounts, but instead defines the standard interface which implementations
|
accounts, but instead defines the standard interface which implementations
|
||||||
should follow so that ANY client can login to ANY home server.
|
should follow so that ANY client can login to ANY home server.
|
||||||
|
|
||||||
The login process breaks down into the following:
|
The login process breaks down into the following:
|
||||||
1. Get login process info.
|
1. Determine the requirements for logging in.
|
||||||
2. Submit the login stage credentials.
|
2. Submit the login stage credentials.
|
||||||
3. Get access token or be told the next stage in the login process and repeat
|
3. Get credentials or be told the next stage in the login process and repeat
|
||||||
step 2.
|
step 2.
|
||||||
|
|
||||||
- What are types?
|
As each home server may have different ways of logging in, the client needs to know how
|
||||||
|
they should login. All distinct login stages MUST have a corresponding ``'type'``.
|
||||||
|
A ``'type'`` is a namespaced string which details the mechanism for logging in.
|
||||||
|
|
||||||
Matrix-defined login types
|
A client may be able to login via multiple valid login flows, and should choose a single
|
||||||
--------------------------
|
flow when logging in. A flow is a series of login stages. The home server MUST respond
|
||||||
- m.login.password
|
with all the valid login flows when requested::
|
||||||
- m.login.oauth2
|
|
||||||
- m.login.email.code
|
|
||||||
- m.login.email.url
|
|
||||||
|
|
||||||
Password-based
|
The client can login via 3 paths: 1a and 1b, 2a and 2b, or 3. The client should
|
||||||
--------------
|
select one of these paths.
|
||||||
Type: "m.login.password"
|
|
||||||
LoginSubmission::
|
[
|
||||||
|
{
|
||||||
{
|
"type": "<login type1a>",
|
||||||
"type": "m.login.password",
|
"stages": [ "<login type 1a>", "<login type 1b>" ]
|
||||||
"user": <user_id>,
|
},
|
||||||
"password": <password>
|
{
|
||||||
}
|
"type": "<login type2a>",
|
||||||
|
"stages": [ "<login type 2a>", "<login type 2b>" ]
|
||||||
Example:
|
},
|
||||||
Assume you are @bob:matrix.org and you wish to login on another mobile device.
|
{
|
||||||
First, you GET /login which returns::
|
"type": "<login type3>"
|
||||||
|
}
|
||||||
{
|
]
|
||||||
"type": "m.login.password"
|
|
||||||
}
|
After the login is completed, the client's fully-qualified user ID and a new access
|
||||||
|
token MUST be returned::
|
||||||
Your client knows how to handle this, so your client prompts the user to enter
|
|
||||||
their username and password. This is then submitted::
|
|
||||||
|
|
||||||
{
|
|
||||||
"type": "m.login.password",
|
|
||||||
"user": "@bob:matrix.org",
|
|
||||||
"password": "monkey"
|
|
||||||
}
|
|
||||||
|
|
||||||
The server checks this, finds it is valid, and returns::
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
"user_id": "@user:matrix.org",
|
||||||
"access_token": "abcdef0123456789"
|
"access_token": "abcdef0123456789"
|
||||||
}
|
}
|
||||||
|
|
||||||
The server may optionally return "user_id" to confirm or change the user's ID.
|
The ``user_id`` key is particularly useful if the home server wishes to support
|
||||||
This is particularly useful if the home server wishes to support localpart entry
|
localpart entry of usernames (e.g. "user" rather than "@user:matrix.org"), as the
|
||||||
of usernames (e.g. "bob" rather than "@bob:matrix.org").
|
client may not be able to determine its ``user_id`` in this case.
|
||||||
|
|
||||||
|
If a login has multiple requests, the home server may wish to create a session. If
|
||||||
|
a home server responds with a 'session' key to a request, clients MUST submit it in
|
||||||
|
subsequent requests until the login is completed::
|
||||||
|
|
||||||
|
{
|
||||||
|
"session": "<session id>"
|
||||||
|
}
|
||||||
|
|
||||||
|
This specification defines the following login types:
|
||||||
|
- m.login.password
|
||||||
|
- m.login.oauth2
|
||||||
|
- m.login.email.code
|
||||||
|
- m.login.email.url
|
||||||
|
|
||||||
|
|
||||||
|
Password-based
|
||||||
|
--------------
|
||||||
|
Type:
|
||||||
|
"m.login.password"
|
||||||
|
Description:
|
||||||
|
Login is supported via a username and password.
|
||||||
|
|
||||||
|
To respond to this type, reply with::
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "m.login.password",
|
||||||
|
"user": "<user_id or user localpart>",
|
||||||
|
"password": "<password>"
|
||||||
|
}
|
||||||
|
|
||||||
|
The home server MUST respond with either new credentials, the next stage of the login
|
||||||
|
process, or a standard error response.
|
||||||
|
|
||||||
OAuth2-based
|
OAuth2-based
|
||||||
------------
|
------------
|
||||||
Type: "m.login.oauth2"
|
Type:
|
||||||
This is a multi-stage login.
|
"m.login.oauth2"
|
||||||
|
Description:
|
||||||
|
Login is supported via OAuth2 URLs. This login consists of multiple requests.
|
||||||
|
|
||||||
LoginSubmission::
|
To respond to this type, reply with::
|
||||||
|
|
||||||
{
|
{
|
||||||
"type": "m.login.oauth2",
|
"type": "m.login.oauth2",
|
||||||
"user": <user_id>
|
"user": "<user_id or user localpart>"
|
||||||
}
|
}
|
||||||
|
|
||||||
Returns::
|
The server MUST respond with::
|
||||||
|
|
||||||
{
|
{
|
||||||
"uri": <Authorization Request uri OR service selection uri>
|
"uri": <Authorization Request URI OR service selection URI>
|
||||||
}
|
}
|
||||||
|
|
||||||
The home server acts as a 'confidential' Client for the purposes of OAuth2.
|
The home server acts as a 'confidential' client for the purposes of OAuth2.
|
||||||
|
If the uri is a ``sevice selection URI``, it MUST point to a webpage which prompts the
|
||||||
If the uri is a "sevice selection uri", it is a simple page which prompts the
|
user to choose which service to authorize with. On selection of a service, this
|
||||||
user to choose which service to authorize with. On selection of a service, they
|
MUST link through to an ``Authorization Request URI``. If there is only 1 service which the
|
||||||
link through to Authorization Request URIs. If there is only 1 service which the
|
|
||||||
home server accepts when logging in, this indirection can be skipped and the
|
home server accepts when logging in, this indirection can be skipped and the
|
||||||
"uri" key can be the Authorization Request URI.
|
"uri" key can be the ``Authorization Request URI``.
|
||||||
|
|
||||||
The client visits the Authorization Request URI, which then shows the OAuth2
|
The client then visits the ``Authorization Request URI``, which then shows the OAuth2
|
||||||
Allow/Deny prompt. Hitting 'Allow' returns the redirect URI with the auth code.
|
Allow/Deny prompt. Hitting 'Allow' returns the ``redirect URI`` with the auth code.
|
||||||
Home servers can choose any path for the redirect URI. The client should visit
|
Home servers can choose any path for the ``redirect URI``. The client should visit
|
||||||
the redirect URI, which will then finish the OAuth2 login process, granting the
|
the ``redirect URI``, which will then finish the OAuth2 login process, granting the
|
||||||
home server an access token for the chosen service. When the home server gets
|
home server an access token for the chosen service. When the home server gets
|
||||||
this access token, it knows that the cilent has authed with the 3rd party, and
|
this access token, it verifies that the cilent has authorised with the 3rd party, and
|
||||||
so can return a LoginResult.
|
can now complete the login. The OAuth2 ``redirect URI`` (with auth code) MUST respond
|
||||||
|
with either new credentials, the next stage of the login process, or a standard error
|
||||||
|
response.
|
||||||
|
|
||||||
The OAuth redirect URI (with auth code) MUST return a LoginResult.
|
For example, if a home server accepts OAuth2 from Google, it would return the
|
||||||
|
Authorization Request URI for Google::
|
||||||
Example:
|
|
||||||
Assume you are @bob:matrix.org and you wish to login on another mobile device.
|
|
||||||
First, you GET /login which returns::
|
|
||||||
|
|
||||||
{
|
|
||||||
"type": "m.login.oauth2"
|
|
||||||
}
|
|
||||||
|
|
||||||
Your client knows how to handle this, so your client prompts the user to enter
|
|
||||||
their username. This is then submitted::
|
|
||||||
|
|
||||||
{
|
|
||||||
"type": "m.login.oauth2",
|
|
||||||
"user": "@bob:matrix.org"
|
|
||||||
}
|
|
||||||
|
|
||||||
The server only accepts auth from Google, so returns the Authorization Request
|
|
||||||
URI for Google::
|
|
||||||
|
|
||||||
{
|
{
|
||||||
"uri": "https://accounts.google.com/o/oauth2/auth?response_type=code&
|
"uri": "https://accounts.google.com/o/oauth2/auth?response_type=code&
|
||||||
|
@ -329,145 +338,142 @@ The client then visits this URI and authorizes the home server. The client then
|
||||||
visits the REDIRECT_URI with the auth code= query parameter which returns::
|
visits the REDIRECT_URI with the auth code= query parameter which returns::
|
||||||
|
|
||||||
{
|
{
|
||||||
|
"user_id": "@user:matrix.org",
|
||||||
"access_token": "0123456789abcdef"
|
"access_token": "0123456789abcdef"
|
||||||
}
|
}
|
||||||
|
|
||||||
Email-based (code)
|
Email-based (code)
|
||||||
------------------
|
------------------
|
||||||
Type: "m.login.email.code"
|
Type:
|
||||||
This is a multi-stage login.
|
"m.login.email.code"
|
||||||
|
Description:
|
||||||
|
Login is supported by typing in a code which is sent in an email. This login
|
||||||
|
consists of multiple requests.
|
||||||
|
|
||||||
First LoginSubmission::
|
To respond to this type, reply with::
|
||||||
|
|
||||||
{
|
{
|
||||||
"type": "m.login.email.code",
|
"type": "m.login.email.code",
|
||||||
"user": <user_id>
|
"user": "<user_id or user localpart>",
|
||||||
"email": <email address>
|
"email": "<email address>"
|
||||||
}
|
}
|
||||||
|
|
||||||
Returns::
|
After validating the email address, the home server MUST send an email containing
|
||||||
|
an authentication code and return::
|
||||||
{
|
|
||||||
"type": m.login.email.code
|
|
||||||
"session": <session id>
|
|
||||||
}
|
|
||||||
|
|
||||||
The email contains a code which must be sent in the next LoginSubmission::
|
|
||||||
|
|
||||||
{
|
{
|
||||||
"type": "m.login.email.code",
|
"type": "m.login.email.code",
|
||||||
"session": <session id>,
|
"session": "<session id>"
|
||||||
"code": <code in email sent>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Returns::
|
The second request in this login stage involves sending this authentication code::
|
||||||
|
|
||||||
{
|
{
|
||||||
"access_token": <access token>
|
"type": "m.login.email.code",
|
||||||
|
"session": "<session id>",
|
||||||
|
"code": "<code in email sent>"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
The home server MUST respond to this with either new credentials, the next stage of
|
||||||
|
the login process, or a standard error response.
|
||||||
|
|
||||||
Email-based (url)
|
Email-based (url)
|
||||||
-----------------
|
-----------------
|
||||||
Type: "m.login.email.url"
|
Type:
|
||||||
This is a multi-stage login.
|
"m.login.email.url"
|
||||||
|
Description:
|
||||||
|
Login is supported by clicking on a URL in an email. This login consists of
|
||||||
|
multiple requests.
|
||||||
|
|
||||||
First LoginSubmission::
|
To respond to this type, reply with::
|
||||||
|
|
||||||
{
|
{
|
||||||
"type": "m.login.email.url",
|
"type": "m.login.email.url",
|
||||||
"user": <user_id>
|
"user": "<user_id or user localpart>",
|
||||||
"email": <email address>
|
"email": "<email address>"
|
||||||
}
|
}
|
||||||
|
|
||||||
Returns::
|
After validating the email address, the home server MUST send an email containing
|
||||||
|
an authentication URL and return::
|
||||||
|
|
||||||
{
|
{
|
||||||
"session": <session id>
|
"type": "m.login.email.url",
|
||||||
|
"session": "<session id>"
|
||||||
}
|
}
|
||||||
|
|
||||||
The email contains a URL which must be clicked. After it has been clicked, the
|
The email contains a URL which must be clicked. After it has been clicked, the
|
||||||
client should perform a request::
|
client should perform another request::
|
||||||
|
|
||||||
{
|
|
||||||
"type": "m.login.email.code",
|
|
||||||
"session": <session id>
|
|
||||||
}
|
|
||||||
|
|
||||||
Returns::
|
|
||||||
|
|
||||||
{
|
|
||||||
"access_token": <access token>
|
|
||||||
}
|
|
||||||
|
|
||||||
Example:
|
|
||||||
Assume you are @bob:matrix.org and you wish to login on another mobile device.
|
|
||||||
First, you GET /login which returns::
|
|
||||||
|
|
||||||
{
|
|
||||||
"type": "m.login.email.url"
|
|
||||||
}
|
|
||||||
|
|
||||||
Your client knows how to handle this, so your client prompts the user to enter
|
|
||||||
their email address. This is then submitted::
|
|
||||||
|
|
||||||
{
|
{
|
||||||
"type": "m.login.email.url",
|
"type": "m.login.email.url",
|
||||||
"user": "@bob:matrix.org",
|
"session": "<session id>"
|
||||||
"email": "bob@mydomain.com"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
The server confirms that bob@mydomain.com is linked to @bob:matrix.org, then
|
The home server MUST respond to this with either new credentials, the next stage of
|
||||||
sends an email to this address and returns::
|
the login process, or a standard error response.
|
||||||
|
|
||||||
|
A common client implementation will be to periodically poll until the link is clicked.
|
||||||
|
If the link has not been visited yet, a standard error response with an errcode of
|
||||||
|
``M_LOGIN_EMAIL_URL_NOT_YET`` should be returned.
|
||||||
|
|
||||||
|
|
||||||
|
N-Factor Authentication
|
||||||
|
-----------------------
|
||||||
|
Multiple login stages can be combined to create N-factor authentication during login.
|
||||||
|
|
||||||
|
This can be achieved by responding with the ``'next'`` login type on completion of a
|
||||||
|
previous login stage::
|
||||||
|
|
||||||
{
|
{
|
||||||
"session": "ewuigf7462"
|
"next": "<next login type>"
|
||||||
}
|
}
|
||||||
|
|
||||||
The client then starts polling the server with the following::
|
If a home server implements N-factor authentication, it MUST respond with all
|
||||||
|
``'stages'`` when initially queried for their login requirements::
|
||||||
|
|
||||||
{
|
{
|
||||||
"type": "m.login.email.url",
|
"type": "<1st login type>",
|
||||||
"session": "ewuigf7462"
|
"stages": [ <1st login type>, <2nd login type>, ... , <Nth login type> ]
|
||||||
}
|
}
|
||||||
|
|
||||||
(Alternatively, the server could send the device a push notification when the
|
This can be represented conceptually as::
|
||||||
email has been validated). The email arrives and it contains a URL to click on.
|
|
||||||
The user clicks on the which completes the login process with the server. The
|
|
||||||
next time the client polls, it returns::
|
|
||||||
|
|
||||||
{
|
_______________________
|
||||||
"access_token": "abcdef0123456789"
|
| Login Stage 1 |
|
||||||
}
|
| type: "<login type1>" |
|
||||||
|
| ___________________ |
|
||||||
N-Factor auth
|
| |_Request_1_________| | <-- Returns "session" key which is used throughout.
|
||||||
-------------
|
| ___________________ |
|
||||||
Multiple login stages can be combined with the "next" key in the LoginResult.
|
| |_Request_2_________| | <-- Returns a "next" value of "login type2"
|
||||||
|
|_______________________|
|
||||||
Example:
|
|
|
||||||
A server demands an email.code then password auth before logging in. First, the
|
|
|
||||||
client performs a GET /login which returns::
|
_________V_____________
|
||||||
|
| Login Stage 2 |
|
||||||
{
|
| type: "<login type2>" |
|
||||||
"type": "m.login.email.code",
|
| ___________________ |
|
||||||
"stages": ["m.login.email.code", "m.login.password"]
|
| |_Request_1_________| |
|
||||||
}
|
| ___________________ |
|
||||||
|
| |_Request_2_________| |
|
||||||
The client performs the email login (See "Email-based (code)"), but instead of
|
| ___________________ |
|
||||||
returning an access_token, it returns::
|
| |_Request_3_________| | <-- Returns a "next" value of "login type3"
|
||||||
|
|_______________________|
|
||||||
{
|
|
|
||||||
"next": "m.login.password"
|
|
|
||||||
}
|
_________V_____________
|
||||||
|
| Login Stage 3 |
|
||||||
The client then presents a user/password screen and the login continues until
|
| type: "<login type3>" |
|
||||||
this is complete (See "Password-based"), which then returns the "access_token".
|
| ___________________ |
|
||||||
|
| |_Request_1_________| | <-- Returns user credentials
|
||||||
|
|_______________________|
|
||||||
|
|
||||||
Fallback
|
Fallback
|
||||||
--------
|
--------
|
||||||
|
Clients cannot be expected to be able to know how to process every single
|
||||||
|
login type. If a client determines it does not know how to handle a given
|
||||||
|
login type, it should request a login fallback page::
|
||||||
|
|
||||||
If the client does NOT know how to handle the given type, they should::
|
GET matrix/client/api/v1/login/fallback
|
||||||
|
|
||||||
GET /login/fallback
|
|
||||||
|
|
||||||
This MUST return an HTML page which can perform the entire login process.
|
This MUST return an HTML page which can perform the entire login process.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue