.. vim: ft=rst .. _token: ===== Token ===== Ubuntu SSO uses tokens of different kinds for different aspects of the service. Currently it knows about the following types of tokens * :ref:`OAuth token ` * :ref:`Password reset token ` * :ref:`Macaroon ` .. _token_oauth: =========== OAuth token =========== An `OAuth token` represents a token used to sign requests using the OAuth 1.0a spec. Data structure ============== * consumer_key * consumer_secret * token_key * token_secret * token_name * date_created * date_updated Use cases ========= .. _token_oauth-create: Create an oauth token --------------------- .. http:post:: /api/v2/tokens/oauth Creates a new OAuth token :form email: user's email address :form password: user's password :form token_name: a name for the token :form otp: one-time password (optional) :status 200: existing token returned :status 201: token created :status 401: invalid credentials or otp password required :status 403: invalid otp provided :status 403: account is suspended or inactive :status 403: email invalidated A consumer requesting an authentication token must provide a *token name*. This name will be used by the *user* to identify the token when doing token management. The recommended scheme for token names is "application_name-device_name". This allows a user to easily identify which tokens belong to which application or to which device. For example they may wish to revoke all tokens for a particular application across their devices, or revoke all tokens on a particular device. If a token name is requested that already exists (for this user) then the existing token will be returned (status code 200) instead of a new one being created (status code 201). If an otp (one-time-password) is provided then it will be checked against any two factor devices registered for the account. If the otp does not match any devices then a 403 will be returned. If an otp is required for the account, but not sent, then a 401 will be returned. Errors ...... * **INVALID_CREDENTIALS**: Provided email/password is not correct. Error status code 401. This error has no additional fields in ``extra``. * **ACCOUNT_SUSPENDED**: Account has been suspended. Error status code 403. This error has no additional fields in ``extra``. * **ACCOUNT_DEACTIVATED**: Account has been deactivated. Error status code 403. This error has no additional fields in ``extra``. * **EMAIL_INVALIDATED**: This email address has been invalidated. Error status code 403. This error has no additional fields in ``extra``. * **TWOFACTOR_REQUIRED**: 2-factor authentication required. Error status code 401. This error has no additional fields in ``extra``. * **TWOFACTOR_FAILURE**: The provided 2-factor key is not recognised. Error status code 403. This error has no additional fields in ``extra``. * **PASSWORD_POLICY_ERROR**: The user's password doesn't comply with the security constraints in force for the account. It must be reset via the web. Error status code 403. The ``extra`` field includes: - ``location``: the domain to visit via the web to reset the password - ``reason``: the reason why the password doesn't comply with the policy * **TOO_MANY_REQUESTS**: Too many requests from the same IP address. Error status code 429. This error has no additional fields in ``extra``. Examples ........ **Request**: .. sourcecode:: http POST /api/v2/tokens/oauth HTTP/1.1 Host: login.ubuntu.com Accept: application/json Content-Type: application/json { "email": "foo@example.com", "password": "thepassword", "token_name": "the-name" } If 2-factor authentication is required: .. sourcecode:: http POST /api/v2/tokens/oauth HTTP/1.1 Host: login.ubuntu.com Accept: application/json Content-Type: application/json { "email": "foo@example.com", "password": "thepassword", "token_name": "the-name", "otp": "123456" } **Response**: .. sourcecode:: http HTTP/1.1 201 CREATED Content-Type: application/json Location: /api/v2/tokens/oauth/the-key { "href": "https://login.ubuntu.com/api/v2/tokens/oauth/the-key", "token_key": "token-key", "token_secret": "token-secret", "token_name": "token-name", "consumer_key": "consumer-key", "consumer_secret": "consumer-secret" "date_created": "2013-01-11 12:43:23", "date_updated": "2013-01-11 12:43:23" } If credentials don't match: .. sourcecode:: http HTTP/1.1 401 UNAUTHORIZED Content-Type: application/json { "code": "INVALID_CREDENTIALS", "message": "Your email/password isn't correct.", "extra": {} } If 2-factor authentication is required: .. sourcecode:: http HTTP/1.1 401 UNAUTHORISED Content-Type: application/json { "code": "TWOFACTOR_REQUIRED", "message": "This account requires 2-factor authentication.", "extra": {} } .. _token_password: ==================== Password reset token ==================== A `password reset token` represents a token used to request a password reset. This token will be generated and an email will be sent to the user's preferred email address including a value that has to be provided when specifying the new password. Data structure ============== * email Use cases ========= .. _token_password-create: Create a password reset token ----------------------------- .. http:post:: /api/v2/tokens/password Creates a new password reset token :form email: user's email address :status 201: token created :status 403: account suspended :status 403: account deactivated :status 403: can not reset password :status 403: email invalidated :status 403: too many tokens A consumer requesting a password reset token must provide an *email* address. This email address will be used to look up the user's account in order to send the user an email containing a *token* that must be provided when setting the new password. To prevent spamming unknowing users by sending multiple password reset emails, only a maximum amount of non-consumed tokens will be allowed to exist at any given time. When such limit is reached, attempting to create a new token will result in an error response. Errors ...... * **ACCOUNT_SUSPENDED**: Account has been suspended. Error status code 403. This error has no additional fields in ``extra``. * **ACCOUNT_DEACTIVATED**: Account has been deactivated. Error status code 403. This error has no additional fields in ``extra``. * **EMAIL_INVALIDATED**: This email address has been invalidated. Error status code 403. This error has no additional fields in ``extra``. * **CAN_NOT_RESET_PASSWORD**: Can not reset password. Error status code 403. This error has no additional fields in ``extra``. * **TOO_MANY_TOKENS**: Too many non-consumed tokens exist. Further token creation is not allowed until existing tokens expire or are consumed. Error status is 403. This error has no additional fields in ``extra``. Examples ........ **Request**: .. sourcecode:: http POST /api/v2/tokens/password HTTP/1.1 Host: login.ubuntu.com Accept: application/json Content-Type: application/json { "email": "foo@example.com" } **Response**: .. sourcecode:: http HTTP/1.1 201 CREATED Content-Type: application/json Location: /api/v2/tokens/password/the-key { "email": "foo@example.com" } If too many tokens exist: .. sourcecode:: http HTTP/1.1 403 FORBIDDEN Content-Type: application/json { "code": "TOO_MANY_TOKENS", "message": "Too many non-consumed tokens exist. Further token creation is not allowed until existing tokens are consumed.", "extra": {} } .. _macaroon: ======== Macaroon ======== A `macaroon` is a bearer token with fine-grained constraints. See the `original paper `_ for details. Ubuntu SSO issues discharge macaroons, which can be bound to macaroons issued by other cooperating services to prove the user's identity. Use cases ========= .. _macaroon_discharge: Issue a discharge macaroon -------------------------- .. http:post:: /api/v2/tokens/discharge Issues a new discharge macaroon :form email: user's email address :form password: user's password :form caveat_id: the caveat ID addressed to Ubuntu SSO from the macaroon that is to be discharged :form otp: one-time password (optional) :status 200: macaroon issued :status 400: invalid request data :status 401: invalid credentials or otp password required :status 403: invalid otp provided :status 403: account is suspended or inactive :status 403: email invalidated :status 403: password does not meet security constraints The service that issued the macaroon that this discharge is to be bound to should have included a caveat in that macaroon addressed to Ubuntu SSO. To issue an appropriate discharge macaroon, the caller must extract the ID of this caveat. This can be done in Python as follows: .. code-block:: python from pymacaroons import Macaroon def extract_caveat_id(macaroon_raw): macaroon = Macaroon.deserialize(macaroon_raw) for caveat in macaroon.caveats: if caveat.location == 'login.ubuntu.com': return caveat.caveat_id else: raise ValueError('No login.ubuntu.com caveat found') If an otp (one-time-password) is provided then it will be checked against any two factor devices registered for the account. If the otp does not match any devices then a 403 will be returned. If an otp is required for the account, but not sent, then a 401 will be returned. Errors ...... * **INVALID_CREDENTIALS**: Provided email/password is not correct. Error status code 401. This error has no additional fields in ``extra``. * **ACCOUNT_SUSPENDED**: Account has been suspended. Error status code 403. This error has no additional fields in ``extra``. * **ACCOUNT_DEACTIVATED**: Account has been deactivated. Error status code 403. This error has no additional fields in ``extra``. * **EMAIL_INVALIDATED**: This email address has been invalidated. Error status code 403. This error has no additional fields in ``extra``. * **TWOFACTOR_REQUIRED**: 2-factor authentication required. Error status code 401. This error has no additional fields in ``extra``. * **TWOFACTOR_FAILURE**: The provided 2-factor key is not recognised. Error status code 403. This error has no additional fields in ``extra``. * **PASSWORD_POLICY_ERROR**: The user's password doesn't comply with the security constraints in force for the account. It must be reset via the web. Error status code 403. The ``extra`` field includes: - ``location``: the domain to visit via the web to reset the password - ``reason``: the reason why the password doesn't comply with the policy * **TOO_MANY_REQUESTS**: Too many requests from the same IP address. Error status code 429. This error has no additional fields in ``extra``. Examples ........ **Request**: .. sourcecode:: http POST /api/v2/tokens/discharge HTTP/1.1 Host: login.ubuntu.com Accept: application/json Content-Type: application/json { "email": "foo@example.com", "password": "thepassword", "caveat_id": "{\"secret\": \"thesecret\", \"version\": 1}" } If 2-factor authentication is required: .. sourcecode:: http POST /api/v2/tokens/discharge HTTP/1.1 Host: login.ubuntu.com Accept: application/json Content-Type: application/json { "email": "foo@example.com", "password": "the-password", "caveat_id": "{\"secret\": \"the-secret\", \"version\": 1}", "otp": "123456" } **Response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "discharge_macaroon": "the-macaroon" } If credentials don't match: .. sourcecode:: http HTTP/1.1 401 UNAUTHORIZED Content-Type: application/json { "error_list": [ { "code": "invalid-credentials", "message": "Provided email/password is not correct." } ] } If 2-factor authentication is required: .. sourcecode:: http HTTP/1.1 401 UNAUTHORIZED Content-Type: application/json { "error_list": [ { "code": "twofactor-required", "message": "2-factor authentication required." } ] } .. _macaroon_refresh: Refresh a discharge macaroon ---------------------------- .. http:post:: /api/v2/tokens/refresh Refreshes a discharge macaroon :form discharge_macaroon: the serialized macaroon to be refreshed :status 200: macaroon refreshed :status 400: invalid request data :status 401: discharge macaroon does not verify :status 403: account is inactive Discharge macaroons are time-limited and must eventually be refreshed. The need for this will be indicated by an error response from the cooperating service. When this happens, the caller should send the old discharge macaroon to this endpoint, which will issue a refreshed version if the original credentials are still valid. Among other reasons, the discharge macaroon may fail to verify if the user's password has changed since it was issued. In this case, the caller must :ref:`request a new discharge macaroon `. Errors ...... * **INVALID_CREDENTIALS**: The provided discharge macaroon is invalid, or the user's password has changed since the discharge macaroon was issued. Error status code 401. This error has no additional fields in ``extra``. * **ACCOUNT_DEACTIVATED**: Account has been deactivated. Error status code 403. This error has no additional fields in ``extra``. Examples ........ **Request**: .. sourcecode:: http POST /api/v2/tokens/refresh HTTP/1.1 Host: login.ubuntu.com Accept: application/json Content-Type: application/json { "discharge_macaroon": "the-old-macaroon" } **Response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "discharge_macaroon": "the-new-macaroon" } If the user's password has changed: .. sourcecode:: http HTTP/1.1 401 UNAUTHORIZED Content-Type: application/json { "error_list": [ { "code": "invalid-credentials", "message": "Provided email/password is not correct." } ] }