|
|
@ -71,10 +71,12 @@ inconsistency.
|
|
|
|
Any errors which occur at the Matrix API level MUST return a "standard
|
|
|
|
Any errors which occur at the Matrix API level MUST return a "standard
|
|
|
|
error response". This is a JSON object which looks like:
|
|
|
|
error response". This is a JSON object which looks like:
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
```json
|
|
|
|
"errcode": "<error code>",
|
|
|
|
{
|
|
|
|
"error": "<error message>"
|
|
|
|
"errcode": "<error code>",
|
|
|
|
}
|
|
|
|
"error": "<error message>"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
The `error` string will be a human-readable error message, usually a
|
|
|
|
The `error` string will be a human-readable error message, usually a
|
|
|
|
sentence explaining what went wrong. The `errcode` string will be a
|
|
|
|
sentence explaining what went wrong. The `errcode` string will be a
|
|
|
@ -439,22 +441,24 @@ homeserver returns an HTTP 401 response, with a JSON body, as follows:
|
|
|
|
HTTP/1.1 401 Unauthorized
|
|
|
|
HTTP/1.1 401 Unauthorized
|
|
|
|
Content-Type: application/json
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
"flows": [
|
|
|
|
{
|
|
|
|
{
|
|
|
|
"flows": [
|
|
|
|
"stages": [ "example.type.foo", "example.type.bar" ]
|
|
|
|
{
|
|
|
|
},
|
|
|
|
"stages": [ "example.type.foo", "example.type.bar" ]
|
|
|
|
{
|
|
|
|
},
|
|
|
|
"stages": [ "example.type.foo", "example.type.baz" ]
|
|
|
|
{
|
|
|
|
|
|
|
|
"stages": [ "example.type.foo", "example.type.baz" ]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
"params": {
|
|
|
|
|
|
|
|
"example.type.baz": {
|
|
|
|
|
|
|
|
"example_key": "foobar"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
"session": "xxxxxx"
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
"params": {
|
|
|
|
|
|
|
|
"example.type.baz": {
|
|
|
|
|
|
|
|
"example_key": "foobar"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
"session": "xxxxxx"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
In addition to the `flows`, this object contains some extra information:
|
|
|
|
In addition to the `flows`, this object contains some extra information:
|
|
|
|
|
|
|
|
|
|
|
@ -482,15 +486,17 @@ type `example.type.foo`, it might submit something like this:
|
|
|
|
POST /_matrix/client/r0/endpoint HTTP/1.1
|
|
|
|
POST /_matrix/client/r0/endpoint HTTP/1.1
|
|
|
|
Content-Type: application/json
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
```json
|
|
|
|
"a_request_parameter": "something",
|
|
|
|
{
|
|
|
|
"another_request_parameter": "something else",
|
|
|
|
"a_request_parameter": "something",
|
|
|
|
"auth": {
|
|
|
|
"another_request_parameter": "something else",
|
|
|
|
"type": "example.type.foo",
|
|
|
|
"auth": {
|
|
|
|
"session": "xxxxxx",
|
|
|
|
"type": "example.type.foo",
|
|
|
|
"example_credential": "verypoorsharedsecret"
|
|
|
|
"session": "xxxxxx",
|
|
|
|
}
|
|
|
|
"example_credential": "verypoorsharedsecret"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
If the homeserver deems the authentication attempt to be successful but
|
|
|
|
If the homeserver deems the authentication attempt to be successful but
|
|
|
|
still requires more stages to be completed, it returns HTTP status 401
|
|
|
|
still requires more stages to be completed, it returns HTTP status 401
|
|
|
@ -501,23 +507,25 @@ client has completed successfully:
|
|
|
|
HTTP/1.1 401 Unauthorized
|
|
|
|
HTTP/1.1 401 Unauthorized
|
|
|
|
Content-Type: application/json
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
"completed": [ "example.type.foo" ],
|
|
|
|
|
|
|
|
"flows": [
|
|
|
|
{
|
|
|
|
{
|
|
|
|
"completed": [ "example.type.foo" ],
|
|
|
|
"stages": [ "example.type.foo", "example.type.bar" ]
|
|
|
|
"flows": [
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
|
"stages": [ "example.type.foo", "example.type.bar" ]
|
|
|
|
"stages": [ "example.type.foo", "example.type.baz" ]
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
"stages": [ "example.type.foo", "example.type.baz" ]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
"params": {
|
|
|
|
|
|
|
|
"example.type.baz": {
|
|
|
|
|
|
|
|
"example_key": "foobar"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
"session": "xxxxxx"
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
"params": {
|
|
|
|
|
|
|
|
"example.type.baz": {
|
|
|
|
|
|
|
|
"example_key": "foobar"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
"session": "xxxxxx"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Individual stages may require more than one request to complete, in
|
|
|
|
Individual stages may require more than one request to complete, in
|
|
|
|
which case the response will be as if the request was unauthenticated
|
|
|
|
which case the response will be as if the request was unauthenticated
|
|
|
@ -531,25 +539,27 @@ status 401 response as above, with the addition of the standard
|
|
|
|
HTTP/1.1 401 Unauthorized
|
|
|
|
HTTP/1.1 401 Unauthorized
|
|
|
|
Content-Type: application/json
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
"errcode": "M_FORBIDDEN",
|
|
|
|
|
|
|
|
"error": "Invalid password",
|
|
|
|
|
|
|
|
"completed": [ "example.type.foo" ],
|
|
|
|
|
|
|
|
"flows": [
|
|
|
|
{
|
|
|
|
{
|
|
|
|
"errcode": "M_FORBIDDEN",
|
|
|
|
"stages": [ "example.type.foo", "example.type.bar" ]
|
|
|
|
"error": "Invalid password",
|
|
|
|
},
|
|
|
|
"completed": [ "example.type.foo" ],
|
|
|
|
{
|
|
|
|
"flows": [
|
|
|
|
"stages": [ "example.type.foo", "example.type.baz" ]
|
|
|
|
{
|
|
|
|
|
|
|
|
"stages": [ "example.type.foo", "example.type.bar" ]
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
"stages": [ "example.type.foo", "example.type.baz" ]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
"params": {
|
|
|
|
|
|
|
|
"example.type.baz": {
|
|
|
|
|
|
|
|
"example_key": "foobar"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
"session": "xxxxxx"
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
"params": {
|
|
|
|
|
|
|
|
"example.type.baz": {
|
|
|
|
|
|
|
|
"example_key": "foobar"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
"session": "xxxxxx"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
If the request fails for a reason other than authentication, the server
|
|
|
|
If the request fails for a reason other than authentication, the server
|
|
|
|
returns an error message in the standard format. For example:
|
|
|
|
returns an error message in the standard format. For example:
|
|
|
@ -557,10 +567,12 @@ returns an error message in the standard format. For example:
|
|
|
|
HTTP/1.1 400 Bad request
|
|
|
|
HTTP/1.1 400 Bad request
|
|
|
|
Content-Type: application/json
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
```json
|
|
|
|
"errcode": "M_EXAMPLE_ERROR",
|
|
|
|
{
|
|
|
|
"error": "Something was wrong"
|
|
|
|
"errcode": "M_EXAMPLE_ERROR",
|
|
|
|
}
|
|
|
|
"error": "Something was wrong"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
If the client has completed all stages of a flow, the homeserver
|
|
|
|
If the client has completed all stages of a flow, the homeserver
|
|
|
|
performs the API call and returns the result as normal. Completed stages
|
|
|
|
performs the API call and returns the result as normal. Completed stages
|
|
|
@ -641,14 +653,16 @@ plain-text.
|
|
|
|
To use this authentication type, clients should submit an auth dict as
|
|
|
|
To use this authentication type, clients should submit an auth dict as
|
|
|
|
follows:
|
|
|
|
follows:
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
```
|
|
|
|
"type": "m.login.password",
|
|
|
|
{
|
|
|
|
"identifier": {
|
|
|
|
"type": "m.login.password",
|
|
|
|
...
|
|
|
|
"identifier": {
|
|
|
|
},
|
|
|
|
...
|
|
|
|
"password": "<password>",
|
|
|
|
},
|
|
|
|
"session": "<session ID>"
|
|
|
|
"password": "<password>",
|
|
|
|
}
|
|
|
|
"session": "<session ID>"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
where the `identifier` property is a user identifier object, as
|
|
|
|
where the `identifier` property is a user identifier object, as
|
|
|
|
described in [Identifier types](#identifier-types).
|
|
|
|
described in [Identifier types](#identifier-types).
|
|
|
@ -656,30 +670,34 @@ described in [Identifier types](#identifier-types).
|
|
|
|
For example, to authenticate using the user's Matrix ID, clients would
|
|
|
|
For example, to authenticate using the user's Matrix ID, clients would
|
|
|
|
submit:
|
|
|
|
submit:
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
```json
|
|
|
|
"type": "m.login.password",
|
|
|
|
{
|
|
|
|
"identifier": {
|
|
|
|
"type": "m.login.password",
|
|
|
|
"type": "m.id.user",
|
|
|
|
"identifier": {
|
|
|
|
"user": "<user_id or user localpart>"
|
|
|
|
"type": "m.id.user",
|
|
|
|
},
|
|
|
|
"user": "<user_id or user localpart>"
|
|
|
|
"password": "<password>",
|
|
|
|
},
|
|
|
|
"session": "<session ID>"
|
|
|
|
"password": "<password>",
|
|
|
|
}
|
|
|
|
"session": "<session ID>"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Alternatively reply using a 3PID bound to the user's account on the
|
|
|
|
Alternatively reply using a 3PID bound to the user's account on the
|
|
|
|
homeserver using the `/account/3pid`\_ API rather than giving the `user`
|
|
|
|
homeserver using the `/account/3pid`\_ API rather than giving the `user`
|
|
|
|
explicitly as follows:
|
|
|
|
explicitly as follows:
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
```json
|
|
|
|
"type": "m.login.password",
|
|
|
|
{
|
|
|
|
"identifier": {
|
|
|
|
"type": "m.login.password",
|
|
|
|
"type": "m.id.thirdparty",
|
|
|
|
"identifier": {
|
|
|
|
"medium": "<The medium of the third party identifier.>",
|
|
|
|
"type": "m.id.thirdparty",
|
|
|
|
"address": "<The third party address of the user>"
|
|
|
|
"medium": "<The medium of the third party identifier.>",
|
|
|
|
},
|
|
|
|
"address": "<The third party address of the user>"
|
|
|
|
"password": "<password>",
|
|
|
|
},
|
|
|
|
"session": "<session ID>"
|
|
|
|
"password": "<password>",
|
|
|
|
}
|
|
|
|
"session": "<session ID>"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
In the case that the homeserver does not know about the supplied 3PID,
|
|
|
|
In the case that the homeserver does not know about the supplied 3PID,
|
|
|
|
the homeserver must respond with 403 Forbidden.
|
|
|
|
the homeserver must respond with 403 Forbidden.
|
|
|
@ -695,11 +713,13 @@ The user completes a Google ReCaptcha 2.0 challenge
|
|
|
|
To use this authentication type, clients should submit an auth dict as
|
|
|
|
To use this authentication type, clients should submit an auth dict as
|
|
|
|
follows:
|
|
|
|
follows:
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
```json
|
|
|
|
"type": "m.login.recaptcha",
|
|
|
|
{
|
|
|
|
"response": "<captcha response>",
|
|
|
|
"type": "m.login.recaptcha",
|
|
|
|
"session": "<session ID>"
|
|
|
|
"response": "<captcha response>",
|
|
|
|
}
|
|
|
|
"session": "<session ID>"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### Single Sign-On
|
|
|
|
#### Single Sign-On
|
|
|
|
|
|
|
|
|
|
|
@ -730,18 +750,20 @@ information should be submitted to the homeserver.
|
|
|
|
To use this authentication type, clients should submit an auth dict as
|
|
|
|
To use this authentication type, clients should submit an auth dict as
|
|
|
|
follows:
|
|
|
|
follows:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
"type": "m.login.email.identity",
|
|
|
|
|
|
|
|
"threepidCreds": [
|
|
|
|
{
|
|
|
|
{
|
|
|
|
"type": "m.login.email.identity",
|
|
|
|
"sid": "<identity server session id>",
|
|
|
|
"threepidCreds": [
|
|
|
|
"client_secret": "<identity server client secret>",
|
|
|
|
{
|
|
|
|
"id_server": "<url of identity server authed with, e.g. 'matrix.org:8090'>",
|
|
|
|
"sid": "<identity server session id>",
|
|
|
|
"id_access_token": "<access token previously registered with the identity server>"
|
|
|
|
"client_secret": "<identity server client secret>",
|
|
|
|
|
|
|
|
"id_server": "<url of identity server authed with, e.g. 'matrix.org:8090'>",
|
|
|
|
|
|
|
|
"id_access_token": "<access token previously registered with the identity server>"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
"session": "<session ID>"
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
"session": "<session ID>"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Note that `id_server` (and therefore `id_access_token`) is optional if
|
|
|
|
Note that `id_server` (and therefore `id_access_token`) is optional if
|
|
|
|
the `/requestToken` request did not include them.
|
|
|
|
the `/requestToken` request did not include them.
|
|
|
@ -762,18 +784,20 @@ information should be submitted to the homeserver.
|
|
|
|
To use this authentication type, clients should submit an auth dict as
|
|
|
|
To use this authentication type, clients should submit an auth dict as
|
|
|
|
follows:
|
|
|
|
follows:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
"type": "m.login.msisdn",
|
|
|
|
|
|
|
|
"threepidCreds": [
|
|
|
|
{
|
|
|
|
{
|
|
|
|
"type": "m.login.msisdn",
|
|
|
|
"sid": "<identity server session id>",
|
|
|
|
"threepidCreds": [
|
|
|
|
"client_secret": "<identity server client secret>",
|
|
|
|
{
|
|
|
|
"id_server": "<url of identity server authed with, e.g. 'matrix.org:8090'>",
|
|
|
|
"sid": "<identity server session id>",
|
|
|
|
"id_access_token": "<access token previously registered with the identity server>"
|
|
|
|
"client_secret": "<identity server client secret>",
|
|
|
|
|
|
|
|
"id_server": "<url of identity server authed with, e.g. 'matrix.org:8090'>",
|
|
|
|
|
|
|
|
"id_access_token": "<access token previously registered with the identity server>"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
"session": "<session ID>"
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
"session": "<session ID>"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Note that `id_server` (and therefore `id_access_token`) is optional if
|
|
|
|
Note that `id_server` (and therefore `id_access_token`) is optional if
|
|
|
|
the `/requestToken` request did not include them.
|
|
|
|
the `/requestToken` request did not include them.
|
|
|
@ -798,10 +822,12 @@ server can instead send flows `m.login.recaptcha, m.login.dummy` and
|
|
|
|
To use this authentication type, clients should submit an auth dict with
|
|
|
|
To use this authentication type, clients should submit an auth dict with
|
|
|
|
just the type and session, if provided:
|
|
|
|
just the type and session, if provided:
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
```json
|
|
|
|
"type": "m.login.dummy",
|
|
|
|
{
|
|
|
|
"session": "<session ID>"
|
|
|
|
"type": "m.login.dummy",
|
|
|
|
}
|
|
|
|
"session": "<session ID>"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
##### Fallback
|
|
|
|
##### Fallback
|
|
|
|
|
|
|
|
|
|
|
@ -820,11 +846,13 @@ This MUST return an HTML page which can perform this authentication
|
|
|
|
stage. This page must use the following JavaScript when the
|
|
|
|
stage. This page must use the following JavaScript when the
|
|
|
|
authentication has been completed:
|
|
|
|
authentication has been completed:
|
|
|
|
|
|
|
|
|
|
|
|
if (window.onAuthDone) {
|
|
|
|
```js
|
|
|
|
window.onAuthDone();
|
|
|
|
if (window.onAuthDone) {
|
|
|
|
} else if (window.opener && window.opener.postMessage) {
|
|
|
|
window.onAuthDone();
|
|
|
|
window.opener.postMessage("authDone", "*");
|
|
|
|
} else if (window.opener && window.opener.postMessage) {
|
|
|
|
}
|
|
|
|
window.opener.postMessage("authDone", "*");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
This allows the client to either arrange for the global function
|
|
|
|
This allows the client to either arrange for the global function
|
|
|
|
`onAuthDone` to be defined in an embedded browser, or to use the HTML5
|
|
|
|
`onAuthDone` to be defined in an embedded browser, or to use the HTML5
|
|
|
@ -836,64 +864,67 @@ Once a client receives the notification that the authentication stage
|
|
|
|
has been completed, it should resubmit the request with an auth dict
|
|
|
|
has been completed, it should resubmit the request with an auth dict
|
|
|
|
with just the session ID:
|
|
|
|
with just the session ID:
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
```json
|
|
|
|
"session": "<session ID>"
|
|
|
|
{
|
|
|
|
}
|
|
|
|
"session": "<session ID>"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### Example
|
|
|
|
#### Example
|
|
|
|
|
|
|
|
|
|
|
|
A client webapp might use the following JavaScript to open a popup
|
|
|
|
A client webapp might use the following JavaScript to open a popup
|
|
|
|
window which will handle unknown login types:
|
|
|
|
window which will handle unknown login types:
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
```js
|
|
|
|
* Arguments:
|
|
|
|
/**
|
|
|
|
* homeserverUrl: the base url of the homeserver (e.g. "https://matrix.org")
|
|
|
|
* Arguments:
|
|
|
|
*
|
|
|
|
* homeserverUrl: the base url of the homeserver (e.g. "https://matrix.org")
|
|
|
|
* apiEndpoint: the API endpoint being used (e.g.
|
|
|
|
*
|
|
|
|
* "/_matrix/client/%CLIENT_MAJOR_VERSION%/account/password")
|
|
|
|
* apiEndpoint: the API endpoint being used (e.g.
|
|
|
|
*
|
|
|
|
* "/_matrix/client/%CLIENT_MAJOR_VERSION%/account/password")
|
|
|
|
* loginType: the loginType being attempted (e.g. "m.login.recaptcha")
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* loginType: the loginType being attempted (e.g. "m.login.recaptcha")
|
|
|
|
* sessionID: the session ID given by the homeserver in earlier requests
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* sessionID: the session ID given by the homeserver in earlier requests
|
|
|
|
* onComplete: a callback which will be called with the results of the request
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
* onComplete: a callback which will be called with the results of the request
|
|
|
|
function unknownLoginType(homeserverUrl, apiEndpoint, loginType, sessionID, onComplete) {
|
|
|
|
*/
|
|
|
|
var popupWindow;
|
|
|
|
function unknownLoginType(homeserverUrl, apiEndpoint, loginType, sessionID, onComplete) {
|
|
|
|
|
|
|
|
var popupWindow;
|
|
|
|
var eventListener = function(ev) {
|
|
|
|
|
|
|
|
// check it's the right message from the right place.
|
|
|
|
var eventListener = function(ev) {
|
|
|
|
if (ev.data !== "authDone" || ev.origin !== homeserverUrl) {
|
|
|
|
// check it's the right message from the right place.
|
|
|
|
return;
|
|
|
|
if (ev.data !== "authDone" || ev.origin !== homeserverUrl) {
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
// close the popup
|
|
|
|
|
|
|
|
popupWindow.close();
|
|
|
|
// close the popup
|
|
|
|
window.removeEventListener("message", eventListener);
|
|
|
|
popupWindow.close();
|
|
|
|
|
|
|
|
window.removeEventListener("message", eventListener);
|
|
|
|
// repeat the request
|
|
|
|
|
|
|
|
var requestBody = {
|
|
|
|
// repeat the request
|
|
|
|
auth: {
|
|
|
|
var requestBody = {
|
|
|
|
session: sessionID,
|
|
|
|
auth: {
|
|
|
|
},
|
|
|
|
session: sessionID,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
request({
|
|
|
|
|
|
|
|
method:'POST', url:apiEndpoint, json:requestBody,
|
|
|
|
|
|
|
|
}, onComplete);
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
window.addEventListener("message", eventListener);
|
|
|
|
request({
|
|
|
|
|
|
|
|
method:'POST', url:apiEndpoint, json:requestBody,
|
|
|
|
|
|
|
|
}, onComplete);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var url = homeserverUrl +
|
|
|
|
window.addEventListener("message", eventListener);
|
|
|
|
"/_matrix/client/%CLIENT_MAJOR_VERSION%/auth/" +
|
|
|
|
|
|
|
|
encodeURIComponent(loginType) +
|
|
|
|
|
|
|
|
"/fallback/web?session=" +
|
|
|
|
|
|
|
|
encodeURIComponent(sessionID);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var url = homeserverUrl +
|
|
|
|
|
|
|
|
"/_matrix/client/%CLIENT_MAJOR_VERSION%/auth/" +
|
|
|
|
|
|
|
|
encodeURIComponent(loginType) +
|
|
|
|
|
|
|
|
"/fallback/web?session=" +
|
|
|
|
|
|
|
|
encodeURIComponent(sessionID);
|
|
|
|
|
|
|
|
|
|
|
|
popupWindow = window.open(url);
|
|
|
|
popupWindow = window.open(url);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
##### Identifier types
|
|
|
|
##### Identifier types
|
|
|
|
|
|
|
|
|
|
|
@ -920,10 +951,12 @@ A client can identify a user using their Matrix ID. This can either be
|
|
|
|
the fully qualified Matrix user ID, or just the localpart of the user
|
|
|
|
the fully qualified Matrix user ID, or just the localpart of the user
|
|
|
|
ID.
|
|
|
|
ID.
|
|
|
|
|
|
|
|
|
|
|
|
"identifier": {
|
|
|
|
```json
|
|
|
|
"type": "m.id.user",
|
|
|
|
"identifier": {
|
|
|
|
"user": "<user_id or user localpart>"
|
|
|
|
"type": "m.id.user",
|
|
|
|
}
|
|
|
|
"user": "<user_id or user localpart>"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### Third-party ID
|
|
|
|
#### Third-party ID
|
|
|
|
|
|
|
|
|
|
|
@ -940,11 +973,13 @@ using the `/account/3pid`\_ API. See the [3PID
|
|
|
|
Types](../appendices.html#pid-types) Appendix for a list of Third-party
|
|
|
|
Types](../appendices.html#pid-types) Appendix for a list of Third-party
|
|
|
|
ID media.
|
|
|
|
ID media.
|
|
|
|
|
|
|
|
|
|
|
|
"identifier": {
|
|
|
|
```json
|
|
|
|
"type": "m.id.thirdparty",
|
|
|
|
"identifier": {
|
|
|
|
"medium": "<The medium of the third party identifier>",
|
|
|
|
"type": "m.id.thirdparty",
|
|
|
|
"address": "<The canonicalised third party address of the user>"
|
|
|
|
"medium": "<The medium of the third party identifier>",
|
|
|
|
}
|
|
|
|
"address": "<The canonicalised third party address of the user>"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### Phone number
|
|
|
|
#### Phone number
|
|
|
|
|
|
|
|
|
|
|
@ -962,11 +997,13 @@ If the client wishes to canonicalise the phone number, then it can use
|
|
|
|
the `m.id.thirdparty` identifier type with a `medium` of `msisdn`
|
|
|
|
the `m.id.thirdparty` identifier type with a `medium` of `msisdn`
|
|
|
|
instead.
|
|
|
|
instead.
|
|
|
|
|
|
|
|
|
|
|
|
"identifier": {
|
|
|
|
```json
|
|
|
|
"type": "m.id.phone",
|
|
|
|
"identifier": {
|
|
|
|
"country": "<The country that the phone number is from>",
|
|
|
|
"type": "m.id.phone",
|
|
|
|
"phone": "<The phone number>"
|
|
|
|
"country": "<The country that the phone number is from>",
|
|
|
|
}
|
|
|
|
"phone": "<The phone number>"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
The `country` is the two-letter uppercase ISO-3166-1 alpha-2 country
|
|
|
|
The `country` is the two-letter uppercase ISO-3166-1 alpha-2 country
|
|
|
|
code that the number in `phone` should be parsed as if it were dialled
|
|
|
|
code that the number in `phone` should be parsed as if it were dialled
|
|
|
@ -983,27 +1020,31 @@ API](#user-interactive-authentication-api).
|
|
|
|
For a simple username/password login, clients should submit a `/login`
|
|
|
|
For a simple username/password login, clients should submit a `/login`
|
|
|
|
request as follows:
|
|
|
|
request as follows:
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
```json
|
|
|
|
"type": "m.login.password",
|
|
|
|
{
|
|
|
|
"identifier": {
|
|
|
|
"type": "m.login.password",
|
|
|
|
"type": "m.id.user",
|
|
|
|
"identifier": {
|
|
|
|
"user": "<user_id or user localpart>"
|
|
|
|
"type": "m.id.user",
|
|
|
|
},
|
|
|
|
"user": "<user_id or user localpart>"
|
|
|
|
"password": "<password>"
|
|
|
|
},
|
|
|
|
}
|
|
|
|
"password": "<password>"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Alternatively, a client can use a 3PID bound to the user's account on
|
|
|
|
Alternatively, a client can use a 3PID bound to the user's account on
|
|
|
|
the homeserver using the `/account/3pid`\_ API rather than giving the
|
|
|
|
the homeserver using the `/account/3pid`\_ API rather than giving the
|
|
|
|
`user` explicitly, as follows:
|
|
|
|
`user` explicitly, as follows:
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
```json
|
|
|
|
"type": "m.login.password",
|
|
|
|
{
|
|
|
|
"identifier": {
|
|
|
|
"type": "m.login.password",
|
|
|
|
"medium": "<The medium of the third party identifier>",
|
|
|
|
"identifier": {
|
|
|
|
"address": "<The canonicalised third party address of the user>"
|
|
|
|
"medium": "<The medium of the third party identifier>",
|
|
|
|
},
|
|
|
|
"address": "<The canonicalised third party address of the user>"
|
|
|
|
"password": "<password>"
|
|
|
|
},
|
|
|
|
}
|
|
|
|
"password": "<password>"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
In the case that the homeserver does not know about the supplied 3PID,
|
|
|
|
In the case that the homeserver does not know about the supplied 3PID,
|
|
|
|
the homeserver must respond with `403 Forbidden`.
|
|
|
|
the homeserver must respond with `403 Forbidden`.
|
|
|
@ -1011,10 +1052,12 @@ the homeserver must respond with `403 Forbidden`.
|
|
|
|
To log in using a login token, clients should submit a `/login` request
|
|
|
|
To log in using a login token, clients should submit a `/login` request
|
|
|
|
as follows:
|
|
|
|
as follows:
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
```json
|
|
|
|
"type": "m.login.token",
|
|
|
|
{
|
|
|
|
"token": "<login token>"
|
|
|
|
"type": "m.login.token",
|
|
|
|
}
|
|
|
|
"token": "<login token>"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
As with [token-based]() interactive login, the `token` must encode the
|
|
|
|
As with [token-based]() interactive login, the `token` must encode the
|
|
|
|
user ID. In the case that the token is not valid, the homeserver must
|
|
|
|
user ID. In the case that the token is not valid, the homeserver must
|
|
|
@ -1166,13 +1209,15 @@ to change their password.
|
|
|
|
|
|
|
|
|
|
|
|
An example of the capability API's response for this capability is:
|
|
|
|
An example of the capability API's response for this capability is:
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
```json
|
|
|
|
"capabilities": {
|
|
|
|
{
|
|
|
|
"m.change_password": {
|
|
|
|
"capabilities": {
|
|
|
|
"enabled": false
|
|
|
|
"m.change_password": {
|
|
|
|
}
|
|
|
|
"enabled": false
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### `m.room_versions` capability
|
|
|
|
### `m.room_versions` capability
|
|
|
|
|
|
|
|
|
|
|
@ -1183,19 +1228,21 @@ upgrade their rooms.
|
|
|
|
|
|
|
|
|
|
|
|
An example of the capability API's response for this capability is:
|
|
|
|
An example of the capability API's response for this capability is:
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
```json
|
|
|
|
"capabilities": {
|
|
|
|
{
|
|
|
|
"m.room_versions": {
|
|
|
|
"capabilities": {
|
|
|
|
"default": "1",
|
|
|
|
"m.room_versions": {
|
|
|
|
"available": {
|
|
|
|
"default": "1",
|
|
|
|
"1": "stable",
|
|
|
|
"available": {
|
|
|
|
"2": "stable",
|
|
|
|
"1": "stable",
|
|
|
|
"3": "unstable",
|
|
|
|
"2": "stable",
|
|
|
|
"custom-version": "unstable"
|
|
|
|
"3": "unstable",
|
|
|
|
}
|
|
|
|
"custom-version": "unstable"
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
This capability mirrors the same restrictions of [room
|
|
|
|
This capability mirrors the same restrictions of [room
|
|
|
|
versions](../index.html#room-versions) to describe which versions are
|
|
|
|
versions](../index.html#room-versions) to describe which versions are
|
|
|
@ -1626,36 +1673,48 @@ There are several APIs provided to `GET` events for a room:
|
|
|
|
|
|
|
|
|
|
|
|
Valid requests look like:
|
|
|
|
Valid requests look like:
|
|
|
|
|
|
|
|
|
|
|
|
PUT /rooms/!roomid:domain/state/m.example.event
|
|
|
|
```
|
|
|
|
{ "key" : "without a state key" }
|
|
|
|
PUT /rooms/!roomid:domain/state/m.example.event
|
|
|
|
|
|
|
|
{ "key" : "without a state key" }
|
|
|
|
PUT /rooms/!roomid:domain/state/m.another.example.event/foo
|
|
|
|
```
|
|
|
|
{ "key" : "with 'foo' as the state key" }
|
|
|
|
```
|
|
|
|
|
|
|
|
PUT /rooms/!roomid:domain/state/m.another.example.event/foo
|
|
|
|
|
|
|
|
{ "key" : "with 'foo' as the state key" }
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
In contrast, these requests are invalid:
|
|
|
|
In contrast, these requests are invalid:
|
|
|
|
|
|
|
|
|
|
|
|
POST /rooms/!roomid:domain/state/m.example.event/
|
|
|
|
```
|
|
|
|
{ "key" : "cannot use POST here" }
|
|
|
|
POST /rooms/!roomid:domain/state/m.example.event/
|
|
|
|
|
|
|
|
{ "key" : "cannot use POST here" }
|
|
|
|
PUT /rooms/!roomid:domain/state/m.another.example.event/foo/11
|
|
|
|
```
|
|
|
|
{ "key" : "txnIds are not supported" }
|
|
|
|
```
|
|
|
|
|
|
|
|
PUT /rooms/!roomid:domain/state/m.another.example.event/foo/11
|
|
|
|
|
|
|
|
{ "key" : "txnIds are not supported" }
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Care should be taken to avoid setting the wrong `state key`:
|
|
|
|
Care should be taken to avoid setting the wrong `state key`:
|
|
|
|
|
|
|
|
|
|
|
|
PUT /rooms/!roomid:domain/state/m.another.example.event/11
|
|
|
|
```
|
|
|
|
{ "key" : "with '11' as the state key, but was probably intended to be a txnId" }
|
|
|
|
PUT /rooms/!roomid:domain/state/m.another.example.event/11
|
|
|
|
|
|
|
|
{ "key" : "with '11' as the state key, but was probably intended to be a txnId" }
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
The `state_key` is often used to store state about individual users, by
|
|
|
|
The `state_key` is often used to store state about individual users, by
|
|
|
|
using the user ID as the `state_key` value. For example:
|
|
|
|
using the user ID as the `state_key` value. For example:
|
|
|
|
|
|
|
|
|
|
|
|
PUT /rooms/!roomid:domain/state/m.favorite.animal.event/%40my_user%3Aexample.org
|
|
|
|
```
|
|
|
|
{ "animal" : "cat", "reason": "fluffy" }
|
|
|
|
PUT /rooms/!roomid:domain/state/m.favorite.animal.event/%40my_user%3Aexample.org
|
|
|
|
|
|
|
|
{ "animal" : "cat", "reason": "fluffy" }
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
In some cases, there may be no need for a `state_key`, so it can be
|
|
|
|
In some cases, there may be no need for a `state_key`, so it can be
|
|
|
|
omitted:
|
|
|
|
omitted:
|
|
|
|
|
|
|
|
|
|
|
|
PUT /rooms/!roomid:domain/state/m.room.bgd.color
|
|
|
|
```
|
|
|
|
{ "color": "red", "hex": "#ff0000" }
|
|
|
|
PUT /rooms/!roomid:domain/state/m.room.bgd.color
|
|
|
|
|
|
|
|
{ "color": "red", "hex": "#ff0000" }
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
{{room\_send\_cs\_http\_api}}
|
|
|
|
{{room\_send\_cs\_http\_api}}
|
|
|
|
|
|
|
|
|
|
|
@ -1872,19 +1931,23 @@ someone, the user performing the ban MUST have the required power level.
|
|
|
|
To ban a user, a request should be made to `/rooms/<room_id>/ban`\_
|
|
|
|
To ban a user, a request should be made to `/rooms/<room_id>/ban`\_
|
|
|
|
with:
|
|
|
|
with:
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
```json
|
|
|
|
"user_id": "<user id to ban>"
|
|
|
|
{
|
|
|
|
"reason": "string: <reason for the ban>"
|
|
|
|
"user_id": "<user id to ban>",
|
|
|
|
}
|
|
|
|
"reason": "string: <reason for the ban>"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
````
|
|
|
|
|
|
|
|
|
|
|
|
Banning a user adjusts the banned member's membership state to `ban`.
|
|
|
|
Banning a user adjusts the banned member's membership state to `ban`.
|
|
|
|
Like with other membership changes, a user can directly adjust the
|
|
|
|
Like with other membership changes, a user can directly adjust the
|
|
|
|
target member's state, by making a request to
|
|
|
|
target member's state, by making a request to
|
|
|
|
`/rooms/<room id>/state/m.room.member/<user id>`:
|
|
|
|
`/rooms/<room id>/state/m.room.member/<user id>`:
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
```json
|
|
|
|
"membership": "ban"
|
|
|
|
{
|
|
|
|
}
|
|
|
|
"membership": "ban"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
A user must be explicitly unbanned with a request to
|
|
|
|
A user must be explicitly unbanned with a request to
|
|
|
|
`/rooms/<room_id>/unban`\_ before they can re-join the room or be
|
|
|
|
`/rooms/<room_id>/unban`\_ before they can re-join the room or be
|
|
|
@ -1938,11 +2001,13 @@ Homeservers SHOULD implement rate limiting to reduce the risk of being
|
|
|
|
overloaded. If a request is refused due to rate limiting, it should
|
|
|
|
overloaded. If a request is refused due to rate limiting, it should
|
|
|
|
return a standard error response of the form:
|
|
|
|
return a standard error response of the form:
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
```json
|
|
|
|
"errcode": "M_LIMIT_EXCEEDED",
|
|
|
|
{
|
|
|
|
"error": "string",
|
|
|
|
"errcode": "M_LIMIT_EXCEEDED",
|
|
|
|
"retry_after_ms": integer (optional)
|
|
|
|
"error": "string",
|
|
|
|
}
|
|
|
|
"retry_after_ms": integer (optional)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
The `retry_after_ms` key SHOULD be included to tell the client how long
|
|
|
|
The `retry_after_ms` key SHOULD be included to tell the client how long
|
|
|
|
they have to wait in milliseconds before they can try again.
|
|
|
|
they have to wait in milliseconds before they can try again.
|
|
|
|