Manage Account

Access to the domain management API is granted to registered and logged in users only. Users can register an account free of charge through the API as described below.

Obtain a Captcha

Before registering a user account, you need to solve a captcha. You will have to send the captcha ID and solution along with your registration request. To obtain a captcha, issue a POST request as follows:

curl -X POST https://desec.io/api/v1/captcha/

The response body will be a JSON object with an id and a challenge field. The value of the id field is the one that you need to fill into the corresponding field of the account registration request. The value of the challenge field is the base64-encoded PNG representation of the captcha itself. You can display it by directing your browser to the URL data:image/png;base64,<challenge>, after replacing <challenge> with the value of the challenge response field.

Captchas expire after 24 hours. IDs are also invalidated after using them in a registration request. This means that if you send an incorrect solution, you will have to obtain a fresh captcha and try again.

Register Account

You can register an account by sending a POST request containing your email address, a password, and a captcha ID and solution (see Obtain a Captcha), like this:

curl -X POST https://desec.io/api/v1/auth/ \
    --header "Content-Type: application/json" --data @- <<EOF
    {
      "email": "youremailaddress@example.com",
      "password": "yourpassword",
      "captcha": {
        "id": "00010203-0405-0607-0809-0a0b0c0d0e0f",
        "solution": "12H45"
      }
    }
EOF

Please consider the following when registering an account:

  • Surrounding whitespace is stripped automatically from passwords.

  • We do not enforce restrictions on your password. However, to maintain a high level of security, make sure to choose a strong password. It is best to generate a long random string consisting of at least 16 alphanumeric characters, and use a password manager instead of attempting to remember it.

  • If you do not require a password at the moment, you can pass null (the JSON value, not the string!). If you create an account this way, it will not be possible to Log In. You can set a password later using the Password Reset procedure.

  • Your email address is required for account recovery in case you forgot your password, for contacting support, etc. It is thus deSEC’s policy to require users to provide an email address and confirm its validity by clicking a verification link sent to that address. (We occasionally also send out announcements of developments at deSEC. To opt out, you can add the outreach_preference: false field to the payload. Note that you will still receive messages about breaking changes.)

  • To facilitate automatic sign-ups, the captcha field in the registration request can be omitted; in this case, the field is required later when completing email verification. In case we find this to cause adverse effects on our systems, we may adopt a captcha-on-registration policy at any time.

When attempting to register a user account, the server will reply with 202 Accepted. In case there already is an account for that email address, nothing else will be done. Otherwise, you will receive an email with a verification link of the form https://desec.io/api/v1/v/activate-account/<code>/. To activate your account, click on that link (which will direct you to our frontend) or send a POST request on the command line. (If a captcha was not provided during registration, it has to be provided now.) The link expires after 12 hours.

If there is a problem with your email address, your password, or the proposed captcha solution, the server will reply with 400 Bad Request and give a human-readable error message that may look like:

HTTP/1.1 400 Bad Request

{
    "password": [
        "This field may not be blank."
    ]
}

Domain Creation during Account Registration

Along with your account creation request, you can provide a domain name as follows:

curl -X POST https://desec.io/api/v1/auth/ \
    --header "Content-Type: application/json" --data @- <<EOF
    {
      "email": "youremailaddress@example.com",
      "password": "yourpassword",
      "captcha": {
        "id": "00010203-0405-0607-0809-0a0b0c0d0e0f",
        "solution": "12H45"
      },
      "domain": "example.org"
    }
EOF

If the domain field is present in the request payload, a DNS domain will be created for this domain name once you activate your account using the verification link that we will send to your email address. If the domain cannot be created (for example, because the domain name is unavailable), your account will be deleted, and you can start over with a fresh registration.

Log In

All interactions with the API that require authentication must be authenticated using a token that identifies the user and authorizes the request. Logging in is the process of obtaining such a token.

In order to log in, you need to confirm your email address first. Afterwards, you can ask the API for a token that can be used to authorize subsequent DNS management requests. To obtain such a token, send a POST request with your email address and password to the /auth/login/ endpoint:

curl -X POST https://desec.io/api/v1/auth/login/ \
    --header "Content-Type: application/json" --data @- <<< \
    '{"email": "youremailaddress@example.com", "password": "yourpassword"}'

If email address and password match our records, the server will reply with 200 OK and return the token secret in the token field of the response body:

{
    "allowed_subnets": [
        "0.0.0.0/0",
        "::/0"
    ],
    "created": "2022-09-06T16:23:24.585329Z",
    "id": "f7ab039b-07b8-493d-ac61-4ddcf903d4de",
    "is_valid": true,
    "last_used": null,
    "max_age": "7 00:00:00",
    "max_unused_period": "01:00:00",
    "name": "",
    "perm_manage_tokens": true,
    "token": "i-T3b1h_OI-H9ab8tRS98stGtURe"
}

As indicated in the response, login tokens expire 7 days after creation or when not used for 1 hour, whichever comes first (see Token Field Reference).

In case of credential mismatch, the server returns 403 Permission Denied.

Note: Every time you send a POST request to this endpoint, an additional token will be created. Existing tokens will remain valid.

To authorize subsequent requests with the new token, set the HTTP Authorization header to the token’s secret value, prefixed with Token:

curl -X GET https://desec.io/api/v1/ \
    --header "Authorization: Token i-T3b1h_OI-H9ab8tRS98stGtURe"

2-Factor Authentication

2-Factor Authentication can be set up through the web interface.

The underlying API keeps evolving as more factors like FIDO2 are getting added, and endpoints are subject to change without notice. A description will be added once the interface is final.

Retrieve Account Information

To request information about your account, send a GET request to the /auth/account/ endpoint:

curl -X GET https://desec.io/api/v1/auth/account/ \
    --header "Authorization: Token i-T3b1h_OI-H9ab8tRS98stGtURe"

A JSON object representing your user account will be returned:

{
    "created": "2019-10-16T18:09:17.715702Z",
    "email": "youremailaddress@example.com",
    "id": "9ab16e5c-805d-4ab1-9030-af3f5a541d47",
    "limit_domains": 15,
    "outreach_preference": true
}

Field details:

created
Access mode:

read-only

Registration timestamp.

email
Access mode:

read-only

Email address associated with the account.

id
Access mode:

read-only

User ID.

limit_domains
Access mode:

read-only

Maximum number of domains the user can create.

outreach_preference
Access mode:

read, write

Type:

boolean

Whether the user is okay with us reaching out by email to inform about developments at deSEC (no ads). Defaults to true.

Modify Account Settings

To change basic information about your account, you can use the usual REST API functionality such as PATCH requests on the /api/v1/auth/account/ endpoint.

Currently, this only allows changing the outreach_preference field. Other fields are either read-only (such as limit_domains) or can be changed through a special procedure only (see e.g. Password Reset).

Password Reset

In case you forget your password, you can reset it. To do so, send a POST request with your email address and a captcha ID and solution (see Obtain a Captcha) to the /auth/account/reset-password/ endpoint:

curl -X POST https://desec.io/api/v1/auth/account/reset-password/ \
    --header "Content-Type: application/json" --data @- <<EOF
    {
      "email": "youremailaddress@example.com",
      "captcha": {
        "id": "00010203-0405-0607-0809-0a0b0c0d0e0f",
        "solution": "12H45"
      }
    }
EOF

The server will reply with 202 Accepted. If there is no account associated with this email address, nothing else will be done. Otherwise, you will receive an email with a URL of the form https://desec.io/api/v1/v/reset-password/<code>/. To perform the actual password reset, click on that link (which will direct you to our frontend) or send a POST request to this URL, with the new password in the payload:

curl -X POST https://desec.io/api/v1/v/reset-password/<code>/ \
    --header "Content-Type: application/json" --data @- <<< \
    '{"new_password": "yournewpassword"}'

This URL expires after 12 hours. It is also invalidated by certain other account-related activities, such as changing your email address.

Once the password was reset successfully, we will send you an email informing you of the event.

Password Change

To change your password, please follow the instructions for Password Reset.

Change Email Address

To change the email address associated with your account, send a POST request with your email address, your password, and your new email address to the /auth/account/change-email/ endpoint:

curl -X POST https://desec.io/api/v1/auth/account/change-email/ \
    --header "Content-Type: application/json" --data @- <<EOF
    {
      "email": "youremailaddress@example.com",
      "password": "yourpassword",
      "new_email": "anotheremailaddress@example.net"
    }
EOF

If the correct password has been provided, the server will reply with 202 Accepted. In case there already is an account for the email address given in the new_email field, nothing else will be done. Otherwise, we will send an email to the new email address for verification purposes. It will contain a link of the form https://desec.io/api/v1/v/change-email/<code>/. To perform the actual change, click on that link (which will direct you to our frontend) or send a POST request on the command line.

The link expires after 12 hours. It is also invalidated by certain other account-related activities, such as changing your password.

Once the email address was changed successfully, we will send a message to the old email address for informational purposes.

Delete Account

Before you can delete your account, it is required to first delete all your domains from deSEC (see Deleting a Domain).

To delete your (empty) account, send a POST request with your email address and password to the /auth/account/delete/ endpoint:

curl -X POST https://desec.io/api/v1/auth/account/delete/ \
    --header "Content-Type: application/json" --data @- <<< \
    '{"email": "youremailaddress@example.com", "password": "yourpassword"}'

If the correct password has been provided, the server will reply with 202 Accepted and send you an email with a link of the form https://desec.io/api/v1/v/delete-account/<code>/. To finish the deletion, click on that link (which will direct you to our frontend) or send a POST request on the command line.

The link expires after 12 hours. It is also invalidated by certain other account-related activities, such as changing your email address or password.

If your account still contains domains, the server will respond with 409 Conflict and not delete your account.

Log Out

To invalidate an authentication token (log out), send a POST request to the the log out endpoint:

curl -X POST https://desec.io/api/v1/auth/logout/ \
    --header "Authorization: Token i-T3b1h_OI-H9ab8tRS98stGtURe"

To delete other tokens based on their ID, see Deleting a Token.

Security Considerations

Confirmation Codes

Some account-related activities require the user to explicitly reaffirm her intent. For this purpose, we send a link with a confirmation code to the user’s email address. Although clients generally should consider these codes opaque, we would like to give some insights into how they work.

The code is a base64-encoded encrypted-then-signed JSON representation of the user’s intent. Encryption/decryption and authentication (sign/verify) is handled by pyca/cryptography’s Fernet implementation which is uses AES-CBC and HMAC-SHA256 with specifically derived key material. The HMAC also signs the current time (i.e. when the intent was expressed). During verification, codes are checked for freshness and rejected when older than allowed.

The encoded intent is composed of the user ID and any extra parameters that were submitted along with the intent. An example of such a parameter is the new email address in the context of a change email address operation. Parameters that are unknown at code generation time are not included in the code and must be provided via POST request payload when using the code. A typical example of this is the new password in a password reset operation, as it is only provided when the code is being used (and not at the time when the code is requested).

In order to prevent race conditions, we augment the code with additional data which we use to invalidate codes when the user state is modified (e.g. by performing another sensitive account operation). This is achieved by including the combined hash of a) the account operation type (e.g. password reset), b) the account’s activation status, c) the account’s current email address, and d) the user’s password hash. When a confirmation code is used, we recompute this hash based on the user’s current state, and only perform the requested action if the hash is reproduced identically. If any of these parameters happens to change before a code is applied, the code will be rendered invalid, and the operation will fail. This measure blocks scenarios such as using an old email address change code after a more recent password change. (Note that it is sometimes possible to revert the state so that an old code becomes valid again, such as when you change the email address twice, with the second change undoing the first one. This issue does not occur for password changes; those do permanently invalidate other codes.)

This approach allows us to securely authenticate sensitive user operations without keeping a list of requested operations on the server. This is both an operational and a privacy advantage. For example, if the user expresses her intent to change the account email address, we do not store that new address on the server until the confirmation code is used (from which the new address is then extracted).

Email verification

Operations that require verification of a new email address (such as when registering first), the server response does not depend on whether another user is already using that address. This is to prevent clients from telling whether a certain email address is registered with deSEC or not.

Verification emails will only be sent out if the email address is not yet associated with an account. Otherwise, nothing will happen.

Also, accounts are created on the server side when the registration request is received (and kept in inactive state). That is, state exists on the server even before the email address is confirmed. Confirmation merely activates the existing account. The purpose of this is to avoid running the risk of sending out large numbers of emails to the same address when a client decides to send multiple registration requests for the same address. In this case, no emails will be sent after the first one.

Password Security

Password information is stored using Django’s default method, PBKDF2.