Skip to main content

Auth Flow

Introduction#

Performing an auth flow is the only to obtain an access token and ID token. This section provides all the routes the frontend SSO application might use.

All routes described in the sequence diagram are not specified in this document. Most of them do no reuqire specific frontend logic. Only the user's agent redirect is required.

Routes are ordered consedering the expected way they should be called.

An auth flow is linked to both authorization and authentication. A description of these concepts can be found in the Authorization & Authentication specification. It is probably worth to read before implement following routes.

Authentication information:

The final ID Token contains information about the authentication performed by the user.

See the list of Authentication Method References and corresponding Authentication Context Classes for more info.

Overall auth flow#

As of today:

  • app.misakey.com: the frontend client
  • auth.misakey.com/_: the Ory Hydra service
  • api.misakey.com: the backend service responsible for authentication

diagram

Initiate an authorization code flow#

Request#

GET https://auth.misakey.com/_/oauth2/auth

Query Parameters:

Response#

Code:

HTTP 302 FOUND

Headers:

HTML Body:

<a href="https://api.misakey.com/auth/login?login_challenge=4f112272f2fa4cbe939b04e74dd3e49e">Found</a>

The Location header contains the same URL than the HTML body. The user's agent should be redirected to this URL to continue the auth flow to the login flow.

Login Flow#

Get Login Information#

This route is used to retrieve information about the current login flow using a login challenge.

Request#

GET https://api.misakey.com/auth/login/info

Query Parameters:

  • login_challenge (string): the login challenge corresponding to the current auth flow.

Response#

Code:

HTTP 200 OK

JSON Body:

{
"client": {
"id": "cc411b8f-28bf-4d4e-abd9-99226b41da27",
"name": "Misakey App",
"logo_uri": "https://media.glassdoor.com/sqll/2449676/misakey-squarelogo-1549446114307.png",
"tos_uri": "https://about.misakey.com/#/fr/legals/tos/",
"policy_uri": "https://media.glassdoor.com/sqll/2449676/misakey-squarelogo-1549446114307.png"
},
"scope": [
"openid"
],
"acr_values": null,
"login_hint": ""
}
  • client (object): information about the SSO client involved in the auth flow:
    • id (uuid string): the unique id.
    • name (string): the name.
    • logo_uri (string) (nullable): web-address of the logo file.
    • policy_uri (string) (nullable): web-address of client privacy policy.
    • tos_uri (string) (nullable): web-address of the client TOS.
  • scope (string): list of scope sent during the auth flow init.
  • acr_values (string) (nullable): list of acr values sent during the auth flow init.
  • login_hint (string): the login_hint sent during the auth flow init.

Require an identity for a given identifier#

This request is idempotent.

This route is used to retrieve information the identity the end-user will log in.

The identity can be a newly created one for the occasion or an existing one. See Response below for more information.

Request#

Headers:

  • The request doesn't require an authorization header.
PUT https://api.misakey.com/auth/identities

JSON Body:

{
"login_challenge": "e45f579fd02d41adbf8cb45e0f6a44ff",
"identifier_value": "auth@test.com",
}
  • login_challenge (string): can be found in preivous redirect URL.
  • identifier_value (string): the identifier value the end-user has entered.

Response#

This route returns the identity the end-user will login as.

Code:

HTTP 200 OK

JSON Body:

{
"identity": {
"display_name": "MUCHMICHMACH@test.com",
"avatar_url": null,
"has_crypto": true,
},
"authn_state": {
"identity_id": "06ac51e7-be00-4219-ac61-f52e7de3f64f",
"current_acr": 0,
"required_acr": 2,
"available_amrs": ["identity:prehashed_password", "identity:emailed_code", "webauthn:webauthn"],
"current_amrs": [],
}
}
  • identity (object): the identity linked to the received identifier value.
    • display_name (string): a customizable display name.
    • avatar_url (string) (nullable): the web address of the end-user avatar file.
    • has_crypto (bool): if the identity has setup crypto or not.
  • authn_state (json): the state of the authentication. This is computed from the identity and NOT from the real current state, so that no information can leak from this unauthenticated endpoint. This therefore can refer to incorrect values if the auth flow is in progress.

Perform an authentication step in the login flow#

The next step to authenticate the end-user is to let them enter some information assuring they own the identity. This is called an authentication step.

Some login flow will require many steps later but as of today, we only have one step even for our most secure flows.

The metadata field contained in the authentication step depends of the method name.

Request#

POST https://api.misakey.com/auth/login/authn-step

Headers:

  • The request doesn't require an authorization header.

JSON Body:

{
"login_challenge": "e2645a0592e94ee78d8fbeaf65a4b82b",
"authn_step": {
"identity_id": "53515d02-642a-4043-a943-bb11c0bdc6a5",
"method_name": "(possibilities defined in the next section)",
"metadata": "(formats defined in the next section)"
}
}
  • login_challenge (string): can be found in previous redirect URL.
  • authn_step (object): the performed authentication step information:
    • identity_id (uuid string): the identity id.
    • method_name (string) (one of: identity:emailed_code, identity:prehashed_password, webauthn:webauthn, totp:totp, totp:recovery): the authentication method used.
    • metadata (json object): metadata containing step information.

The list of possible formats is defined in the next section.

Metadata field formats as input#

This section describes the possible metadata format, as a JSON object, which is a field contained in the JSON body of the previous section.

The context of this specification is the performing of an authentication step only.

tip

Metadata as output formats are described here and differ a bit.

Expected method formats descriptions 🔗
identity:emailed_code
identity:prehashed_password
webauthn:webauthn
totp:totp
totp:recovery
emailed_code method format as input#

JSON Body:

{
[...]
"method_name": "identity:emailed_code",
"metadata": {
"code": "320028"
},
[...]
}
prehashed_password method format as input#

⚠️ Warning, the metadata has not the exact same shape as the metadata returned requiring an identity with the prehashed_password value as preferred method, which contains only the hash parameters of the password.

{
[...]
"method_name": "identity:prehashed_password",
"metadata": {
"hash_base_64": "Ym9uam91ciBmbG9yZW50IGNvbW1lbnQgdmFzLXR1IGVuIGNldHRlIGJlbGxlIGpvdXJuw6llID8h",
"params": {
"salt_base_64": "Yydlc3QgdmFjaGVtZW50IHNhbMOpZSBjb21tZSBwaHJhc2UgZW5jb2TDqWUgZW4gYmFzZSA2NA==",
"memory": 1024,
"iterations": 1,
"parallelism": 1
}
},
[...]
}
webauthn method format as input#
{
[...]
"method_name": "webauthn:webauthn",
"metadata": {
"id":"<string>",
"rawId":"<string>",
"response":{
"clientDataJSON":"<string>",
"authenticatorData":"<string>",
"signature":"<string>",
"userHandle":"<string>"
},
"type":"<string>"
},
[...]
}

The metadata content is explained in the webauthn documentation

totp method format as input#
{
[...]
"method_name": "totp:totp",
"metadata": {
"code": "<string>",
"recovery_code": "<string>"
},
[...]
}

The code must be the otp given by the external app.

totp recovery method format as input#
{
[...]
"method_name": "totp:recovery",
"metadata": {
"recovery_code": "<string>"
},
[...]
}

The recovery_code must be in the user recovery codes set.

Response#

On success, the route can return two possible json body:

the "redirect" response#

What is returned is the next URL the user's agent should be redirected to. This response is given when the authentication server consider the end-user has proven its identity sufficiently.

The access token is sent and stored in an http-only cookie.

Code:

HTTP 200 OK

JSON Body:

{
"next": "redirect",
"redirect_to": "https://auth.misakey.com/_/oauth2/auth",
}
  • next (oneof: redirect, authn_step): the next action the authentication server is waiting for.
  • redirect_to (string): the URL the user's agent should be redirected to.

The "more authentication required" response#

What is returned is the next authentication step the end-user should perform. This response is given when the authentication server requires more authentication step to proove the end-user identity.

Technically, it happens when the current ACR, corresponding to previously validated authentication steps (a.k.a. AMRs), is below the expected ACR.

The expected ACR can be set by:

  • the Relying Party expectations: acr_values paramenter on the init of the auth flow.
  • the choosen identity configuration.

Also part of the response, an access token that must be used for the next request as an accesstoken cookie. This token allows us to authorize more advanced calls.

Code:

HTTP 200 OK

JSON Body:

{
"next": "",
"authn_state": {
"identity_id": "06ac51e7-be00-4219-ac61-f52e7de3f64f",
"current_acr": 1,
"required_acr": 2,
"available_amrs": ["webauthn:webauthn"],
"current_amrs": ["identity:prehashed_password"],
}
}
  • next (oneof: redirect): the next action the authentication server is waiting for.
  • authn_step (object): the next expected authn step to end the login flow.

Cookies:

  • authnaccesstoken: (string) an access token allowing more advanced requests while being still in the login flow.
  • authntokentype: (string) the token type.

Notable error responses#

On error during an authentication step, some information might be displayed to the end-user.

1. Received code is invalid:

This error occurs when the code received in metadata does not match any stored code.

Code:

HTTP 403 FORBIDDEN

JSON Body:

{
"code": "forbidden",
"origin": "body",
"details": {
"code": "invalid",
},
}

2. Received code has expired:

This error occurs when the code received in metadata is correct but the timebox to use it is expired.

Code:

HTTP 403 FORBIDDEN

JSON Body:

{
"code": "forbidden",
"origin": "body",
"details": {
"code": "expired",
},
}

3. The Authorization headers do not correspond to the login_challenge:

Situation when the error is returned:

  1. The end-user has performed an authentication step in a login flow A.
  2. The end-user refreshes their agent, it inits a new login flow B.
  3. The client has still the access token bound to the login flow A in headers.

The access token is valid for the login flow A but cannot be used in the login flow B.

Code:

HTTP 403 FORBIDDEN

JSON Body:

{
"code": "forbidden",
"origin": "headers",
"desc": "...",
"details": {
"Authorization": "conflict",
"login_challenge": "conflict"
}
}

Init a new authentication step#

This endpoint allows to init an authentication step:

  • to get information about the step (e.g.: identity:prehashed_password, webauthn:webauthn)
  • to init a new step (e.g.: identity:emailed_code)

Request#

POST https://api.misakey.com/authn-steps
{
"login_challenge": "e45f579fd02d41adbf8cb45e0f6a44ff",
"authn_step": {
"identity_id": "fed6784f-913b-49cb-9174-a8b7dc6bc675",
"method_name": "identity:emailed_code"
}
}

Headers:

  • The request doesn't require an authorization header.

JSON Body:

  • login_challenge (string): can be found in previous redirect URL.
  • authn_step (object): the initiated authentication step information:
    • identity_id (uuid string): the identity ID for which the authentication step will be initialized.
    • method_name (string) (one of: identity:emailed_code, identity:prehashed_password, webauthn:webauthn, totp:totp, totp:recovery): the method used by the authentication step.

Response#

The response is the step metadata, described in the next section.

Code:

HTTP 200 OK

Notable error responses#

On errors, some information should be displayed to the end-user.

1. A similar authn step already exists:

This error occurs when an authentication step already exists for this identity_id and method_name

Code:

HTTP 409 Conflict
{
"code": "conflict",
"origin": "body",
"desc": "initing an authn step: a code has already been generated",
"details": {
"identity_id": "conflict",
"method_name": "conflict"
}
}

2. Impossible to perform a prehashed_password method with the identity:

This error occurs when the identity has no linked account. The password being attached to the account, such an authentication method is impossible to be handled.

Code:

HTTP 409 Conflict
{
"code": "conflict",
"origin": "body",
"desc": "initing an authn step: identity has no linked account",
"details": {
"identity_id": "conflict",
"account_id": "required"
}
}

Metadata field formats as output#

Considering the preferred/expected authentication method, the metadata on output can contain additional information.

tip

Metadata as input formats are defined here and differ a bit.

Expected method formats descriptions 🔗
identity:emailed_code
identity:prehashed_password
webauthn:webauthn
totp:totp
totp:recovery

emailed_code method format as output#

{
[...]
"method_name": "identity:emailed_code",
"metadata": null,
[...]
}

prehashed_password method format as output#

On identity:prehashed_password, the metadata field contains information about how the password is supposed to be prehashed.

⚠️ Warning, the metadata has not the exact same shape as the metadata used to perform an authentication step using the prehashed_password method, which also contains the hash of the password.

{
[...]
"method_name": "identity:prehashed_password",
"metadata": {
"salt_base_64": "Yydlc3QgdmFjaGVtZW50IHNhbMOpZSBjb21tZSBwaHJhc2UgZW5jb2TDqWUgZW4gYmFzZSA2NA==",
"memory": 1024,
"iterations": 1,
"parallelism": 1
},
[...]
}

webauthn method format as output#

{
[...]
"method_name": "webauthn:webauthn",
"metadata":
{
"publicKey": {
"challenge":"<string>",
"timeout":<int>,
"rpId":"<string>",
"allowCredentials":[{
"type":"<string>",
"id":"<string>"
},{
"type":"<string>",
"id":"<string>"
}]
}
},
[...]
}

The metadata content is defined and explained in the webauthn documentation.

totp method format as output#

{
[...]
"method_name": "totp:totp",
"metadata": null,
[...]
}

totp recovery method format as output#

{
[...]
"method_name": "totp:recovery",
"metadata": null,
[...]
}

Consent Flow#

Get Consent Information#

This route is used to retrieve information about the current consent flow using a consent challenge.

Request#

GET https://api.misakey.com/auth/consent/info

Query Parameters:

  • consent_challenge (string): the consent challenge corresponding to the current auth flow.

Response#

Code:

HTTP 200 OK

JSON Body:

{
"subject": "f058a198-e5e7-4d96-8b71-e6aa1edd3eb5",
"acr": "2",
"scope": [
"openid",
"tos",
"privacy_policy"
],
"context": {
"amr": "emailed_code"
},
"client": {
"id": "cc411b8f-28bf-4d4e-abd9-99226b41da27",
"name": "Misakey App",
"logo_uri": "https://media.glassdoor.com/sqll/2449676/misakey-squarelogo-1549446114307.png"
}
}
  • subject (uuid string): unique id of the account getting the token
  • acr (string): the acr level for the current flow
  • scope (string): list of scope sent during the auth flow init.
  • context (object): context of the current consent flow
  • client (object): information about the SSO client involved in the auth flow:
    • id (uuid string): the unique id.
    • name (string): the name.
    • url (string) (nullable): web-address of the logo file.

Accept the consent request in the consent flow#

This lets the user choose the scopes they want to accept.

For the moment, those scopes are limited to tos and privacy_policy

Request#

POST https://api.misakey.com/auth/consent

Headers:

  • The request doesn't require an authorization header.

JSON Body:

{
"consent_challenge": "e2645a0592e94ee78d8fbeaf65a4b82b",
"identity_id": "53515d02-642a-4043-a943-bb11c0bdc6a5",
"consented_scopes": [
"tos",
"privacy_policy"
]
}
  • consent_challenge (string): can be found in previous redirect URL.
  • identity_id (uuid string): the identity id bound to the identifier of the flow.
  • consented_scopes (list of string) (one of: tos, privacy_policy): the accepted scopes.

Response#

On success, the route returns the next URL to redirect the user's agent.

Code:

HTTP 200 OK

JSON Body:

{
"redirect_to": "https://auth.misakey.com/_/oauth2/auth"
}
  • redirect_to (string): the URL the user's agent should be redirected to.

Notable error responses#

1 - A mandatory scope is missing from consent

If some legal scopes have been requested at the init of the auth flow, they must be consented in all cases on this request.

Here is the error to expect if the client didn't send these scopes:

{
"code": "forbidden",
"origin": "unknown",
"details": {
"requested_legal_scope": "{space-limited list of legal scope requested}",
"consented_legal_scope": "{space-limited list of legal scope consented}"
}
}

Others#

Reset the auth flow#

This requests allow the complete restart of the auth flow. It triggers a redirection to the initial auth request if found (using the login_challenge sent in parameter). If no auth request is found, it redirects the end-user to a blank connection screen on the Misakey main app (without any information about the initial flow).

⚠️ be aware this action invalidates the session for the whole account in this case.

Request#

GET https://api.misakey.com/auth/reset?login_challenge=4f112272f2fa4cbe939b04e74dd3e49e

Query Parameters:

  • login_challenge (string) (optional): the login challenge corresponding to the current auth flow. On invalid or missing, the user's agent will be redirected to the home page.

Response#

Code:

HTTP 302 FOUND

Headers:

HTML Body:

<a href="https://auth.misakey.com/_/oauth2/auth/>Found</a>

The Location header contains the same URL than the HTML body. The user's agent should be redirected to this URL to continue the auth flow to the login flow.

Logout#

This request logouts a user from their authentication session.

An authentication session is valid for an identity but it potentially links other identities through the account relationship, be aware this action invalidates the session for the whole account in this case.

Request#

POST https://api.misakey.com/auth/logout
  • accesstoken (opaque token) (ACR >= 0): mid claim as the identity id sent in body.
  • tokentype: must be bearer

Headers:

  • X-CSRF-Token: a token to prevent from CSRF attacks.

Response#

This route does not return any content.

Code:

HTTP 204 NO CONTENT

Get Secret Storage#

This endpoint allows to get the account secret storage during the auth flow.

This endpoint needs a valid process token.

Request#

GET https://api.misakey.com.local/auth/secret-storage

Query Parameters:

  • login_challenge (string): the login challenge corresponding to the current auth flow.
  • identity_id (string) (uuid4): the id of the identity corresponding to the current auth flow.

Headers:

  • Authorization: should be Bearer {opaque_token} with opaque token being the login_challenge of the auth flow.

Response#

Code:

HTTP 200 OK

JSON Body:

{
"account_id": "d8aa7d0f-81fe-4e66-99d5-fe2b31360ae0",
"secrets": {
"account_root_key": {
"key_hash": "V2Wrv7LjW_Ct_LPTuDcHSg",
"encrypted_key": "JgdIJAGfImLyUlkk2eG5tQ"
},
"vault_key": {
"key_hash": "JoUZHeHJ6zaz6vRw_Padgg",
"encrypted_key": "RDTEMIlE4JlMAofbaF_VpQ"
},
"asym_keys": {
"AbKozlB19lF8mGp0NURW0A": {
"encrypted_secret_key": "DG5x6eRi9W56_BJpst5dgZCmu0O-s2gmkY_CPFkutF8"
},
"YobcbIi45V68XFOyU_q4nQ": {
"encrypted_secret_key": "Tl53fZahxhijbuWH3qWkqOSDodt5UhlyNRVSyAegIpY"
}
},
"box_key_shares": {}
}
}
  • account_id (string) (uuid4): the id of the account related to the current auth flow.
  • secrets (object): the content of the account's secret storage.

Get Backup#

This endpoint allows to get the account backup during the auth flow.

(Note that secret backup system is not used anymore, but this endpoint is needed for the frontend to migrate account still using it to the new secret storage system)

This endpoint needs a valid process token.

Request#

GET https://api.misakey.com.local/auth/backup

Query Parameters:

  • login_challenge (string): the login challenge corresponding to the current auth flow.
  • identity_id (string) (uuid4): the id of the identity corresponding to the current auth flow.

Headers:

  • Authorization: should be Bearer {opaque_token} with opaque token being the login_challenge of the auth flow.

Response#

Code:

HTTP 200 OK

JSON Body:

{
"data": "[STRINGIFIED JSON]",
"version": 3,
"account_id": "d8aa7d0f-81fe-4e66-99d5-fe2b31360ae0"
}
  • data (string): the user backup data.
  • version (integer): the current backup version.
  • account_id (string) (uuid4): the id of the account owning the backup.

Creating a Root Key Share#

This endpoint allows to create a root key share in the auth flow.

Request#

POST https://api.misakey.com/auth/root-key-shares

Headers:

  • Authorization: should be Bearer {opaque_token} with opaque token being the access token given during the auth flow.

JSON Body:

{
"share": "o0hYlc2RurzJTiXldnnOMw",
"user_local_share_hash": "axoGoSxJDiVWru3Sm-vdYQ"
}
  • share (string) (base64): one of the shares.
  • user_local_share_hash (string) (unpadded url-safe base64): a hash of the other share.

Response#

Code:

HTTP 201 CREATED

JSON Body:

{
"account_id": "b2dc8b7e-44e6-4510-b222-c914876fad1c",
"share": "o0hYlc2RurzJTiXldnnOMw",
"user_local_share_hash": "axoGoSxJDiVWru3Sm-vdYQ"
}

OIDC endpoints#

These endpoints are openid RFC-compliant endpoints.

Get User Info#

This endpoint basically allow to get some of the ID token info.

It must be authenticated.

Request#

GET https://api.misakey.com/auth/userinfo

Cookies:

  • accesstoken (opaque token) (ACR >= 1)
  • tokentype: must be bearer

Response#

Code:

HTTP 200 OK

JSON Body:

{
"acr": "2",
"aid": "97db9036-4190-4374-b0d1-0775b55f4e94",
"amr": [
"browser_cookie"
],
"email": "joni@misakey.com",
"mid": "aba11ab7-a077-4520-b76c-dba9fac01693",
"sco": "openid tos privacy_policy",
"sid": "562e4b78-86d2-4674-b80a-79dcfffb5d38",
"sub": "2828b8d0-439c-4326-b49b-2736bd6eacb7"
}
  • acr (string): ACR corresponding to the currrent token,
  • amr (string array): the way the user got the token
  • email (string): the user email,
  • sco (string): list of space separated scopes linked to the token,
  • sid (string): the session identifier,
  • sub (string): the user identifier,
  • mid (string): the Misakey specific identifier,
  • aid (string): the user account identifier,