Manage Tokens¶
To make authentication more flexible, you can create and configure multiple authentication tokens. To that end, we provide a set of token management endpoints that are separate from the login and logout endpoints. The most notable differences are that the login endpoint needs authentication with the user credentials (email address and password) and its purpose is to return a token with a broad range of permissions, whereas the token management endpoints are authenticated using an already issued token, for the purpose of configuring more fine-grained token permissions.
When accessing the token management endpoints using a token without sufficient
permission, the server will reply with 403 Forbidden
.
Token Field Reference¶
A JSON object representing a token has the following structure:
{
"created": "2018-09-06T09:08:43.762697Z",
"id": "3a6b94b5-d20e-40bd-a7cc-521f5c79fab3",
"last_used": null,
"name": "my new token",
"perm_manage_tokens": false,
"allowed_subnets": [
"0.0.0.0/0",
"::/0"
],
"max_age": "365 00:00:00",
"max_unused_period": null,
"token": "4pnk7u-NHvrEkFzrhFDRTjGFyX_S"
}
Field details:
allowed_subnets
- Access mode:
read, write
- Type:
Array of IPs or IP subnets
Exhaustive list of IP addresses or subnets clients must connect from in order to successfully authenticate with the token. Both IPv4 and IPv6 are supported. Defaults to
0.0.0.0/0, ::/0
(no restriction).created
- Access mode:
read-only
- Type:
timestamp
Timestamp of token creation, in ISO 8601 format (e.g.
2018-09-06T09:08:43.762697Z
).id
- Access mode:
read-only
- Type:
UUID
Token ID, used for identification only (e.g. when deleting a token). This is not the token’s secret value.
is_valid
- Access mode:
read-only
- Type:
boolean
Indicates whether this token is valid. Currently, this reflects validity based on
max_age
andmax_unused_period
.last_used
- Access mode:
read-only
- Type:
timestamp or
null
Timestamp of when the token was last successfully authenticated, or
null
if the token has never been used.In most cases, this corresponds to the last time when an API operation was performed using this token. However, if the operation was not executed because it was found that the token did not have sufficient permission, this field will still be updated.
max_age
- Access mode:
read, write
- Type:
string (time duration:
[DD] [HH:[MM:]]ss[.uuuuuu]
) ornull
Maximum token age. If
created + max_age
is less than the current time, the token is invalidated. Invalidated tokens are not automatically deleted and can be resurrected by adjusting the expiration settings (using another valid token with sufficient privileges).If
null
, the token is valid regardless of age (setting disabled).max_unused_period
- Access mode:
read, write
- Type:
string (time duration:
[DD] [HH:[MM:]]ss[.uuuuuu]
) ornull
Maximum allowed time period of disuse without invalidating the token. If
max(created, last_used) + max_unused_period
is less than the current time, the token is invalidated. Invalidated tokens are not automatically deleted and can be resurrected by adjusting the expiration settings (using another valid token with sufficient privileges).If
null
, the token is valid regardless of prior usage (setting disabled).name
- Access mode:
read, write
- Type:
string
Token name. It is meant for user reference only and carries no operational meaning. If omitted, the empty string is assumed. The maximum length is 178.
Certain API operations will automatically populate the
name
field with suitable values such as “login” or “dyndns”.perm_manage_tokens
- Access mode:
read, write
- Type:
boolean
Permission to manage tokens (this one and also all others). A token which does not have this flag set cannot access the
auth/tokens/
endpoints.token
- Access mode:
read-once
- Type:
string
The token’s secret value that is used to authenticate API requests. It is only returned once, upon creation of the token. The secret value of an existing token cannot be recovered (we store it in irreversibly hashed form). For security details, see Security Considerations.
Creating a Token¶
To create a new token, issue a POST
request to the tokens endpoint:
curl -X POST https://desec.io/api/v1/auth/tokens/ \
--header "Authorization: Token mu4W4MHuSc0Hy-GD1h_dnKuZBond" \
--header "Content-Type: application/json" --data @- <<< \
'{"name": "my new token"}'
Note that the name and other fields are optional. The server will reply with
201 Created
and the created token in the response body:
{
"created": "2018-09-06T09:08:43.762697Z",
"id": "3a6b94b5-d20e-40bd-a7cc-521f5c79fab3",
"last_used": null,
"name": "my new token",
"perm_manage_tokens": false,
"allowed_subnets": [
"0.0.0.0/0",
"::/0"
],
"token": "4pnk7u-NHvrEkFzrhFDRTjGFyX_S"
}
The new token will, by default, possess fewer permissions than a login token.
In particular, the perm_manage_tokens
flag will not be set, so that the
new token cannot be used to retrieve, modify, or delete any tokens (including
itself).
With the default set of permissions, tokens qualify for carrying out all API operations related to DNS management (i.e. managing both domains and DNS records). Note that it is always possible to use the Log Out endpoint to delete a token.
If you require tokens with extra permissions, you can provide the desired configuration during creation:
allowed_subnets
: In this field, you can list the IP addresses (or subnets) that clients must connect from in order to use the token. If not provided, access is not restricted based on the IP address. Both IPv4 and IPv6 are supported.perm_manage_tokens
: If set totrue
, the token can be used to authorize token management operations (as described in this chapter).
Additionally, you can configure an expiration policy with the following fields:
max_age
: Force token expiration when a certain time period has passed since its creation. Ifnull
, the token does not expire due to age.max_unused_period
: Require that the token is used a least once within the given time period to prevent it from expiring. Ifnull
, the token does not expire due to it not being used.
If a field is provided but has invalid content, 400 Bad Request
is
returned, with error details in the body.
Modifying a Token¶
To modify a token, send a PATCH
or PUT
request to the
auth/tokens/{id}/
endpoint of the token you would like to modify:
curl -X PATCH https://desec.io/api/v1/auth/tokens/{id}/ \
--header "Authorization: Token mu4W4MHuSc0Hy-GD1h_dnKuZBond" \
--header "Content-Type: application/json" --data @- <<< \
'{"name": "my new token"}'
The ID given in the URL is the ID of the token that will be modified. Upon
success, the server will reply with 200 OK
.
The token given in the Authorization
header requires the
perm_manage_tokens
permission. If permissions are insufficient, the
server will return 403 Forbidden
.
name
and all other fields are optional. The list of fields that can be
given is the same as when Creating a Token. If a field is provided but has
invalid content, 400 Bad Request
is returned, with error details in the
body.
Note: As long as the perm_manage_tokens
permission is in effect, it
is possible for a token to grant and revoke its own permissions. However, if
the perm_manage_tokens
permission is removed, the operation can only be
reversed by means of another token that has this permission.
Listing Tokens¶
To retrieve a list of all known tokens, issue a GET
request as follows:
curl -X GET https://desec.io/api/v1/auth/tokens/ \
--header "Authorization: Token mu4W4MHuSc0Hy-GD1h_dnKuZBond"
The server will respond with a list of token objects. Up to 500 items are returned at a time. If you have a larger number of tokens configured, the use of Pagination is required.
Retrieving a Specific Token¶
To retrieve information about a specific token, issue a GET
request to the
token’s endpoint:
curl -X GET https://desec.io/api/v1/auth/tokens/{id}/ \
--header "Authorization: Token mu4W4MHuSc0Hy-GD1h_dnKuZBond"
The response will contain a token object as described under Token Field Reference. You can use it to check a token’s properties, such as name, timestamps of creation and last use, or permissions.
Note: The response does not contain the token’s secret value!
Deleting a Token¶
To delete an existing token by its ID via the token management endpoints, issue a
DELETE
request on the token’s endpoint, replacing {id}
with the
token id
value:
curl -X DELETE https://desec.io/api/v1/auth/tokens/{id}/ \
--header "Authorization: Token mu4W4MHuSc0Hy-GD1h_dnKuZBond"
The server will reply with 204 No Content
, even if the token was not found.
If you do not have the token ID, but you do have the token secret, you can use the Log Out endpoint to delete it.
Token Scoping: Policies¶
Tokens by default can be used to authorize arbitrary actions within the user’s account, including DNS operations on any domain and some administrative tasks. As such, tokens are considered privileged when no further configuration is done. (This applies to v1 of the API and may change in a later version.)
Tokens can be restricted using Token Policies, which narrow down the scope of influence for a given API token. Using policies, the token’s power can be limited in two ways:
the type of access control (allow-by-default or deny-by-default) for DNS write operations, such as dynDNS updates or general RRset management;
explicit access control for specific RRsets through the policy’s
domain
,subname
, andtype
fields.
All tokens can, regardless of their policy configuration, read any RRset (for
all domains in the account). This is because essentially the same information
is also available through the DNS. Note that the API in addition exposes some
metadata, such as the RRset’s created
or touched
timestamps.
Write permissions can be configured on a per-RRset basis. When attempting to manipulate an RRset, the applicable policy is identified by matching the RRset against existing policies in the following order:
Priority |
|
|
|
---|---|---|---|
1 |
match |
match |
match |
2 |
match |
match |
null |
3 |
match |
null |
match |
4 |
match |
null |
null |
5 |
null |
match |
match |
6 |
null |
match |
null |
7 |
null |
null |
match |
8 |
null |
null |
null |
Taking the (domain
, subname
, type
) tuple as a path, this can be
considered a longest-prefix match algorithm. Wildcards are not expanded and
match only RRsets with an identical wildcard subname
.
RRsets for which no more specific policy is configured are eventually caught by the token’s default policy. It is therefore required to create such a default policy before any more specific policies can be created on a given token.
Tokens with at least one policy are considered restricted, with their scope limited to DNS record management. They can neither Retrieve Account Information nor perform Domain Management (such as domain creation or deletion).
Note: Token policies are independent of high-level token permissions
that can be assigned when Creating a Token.
In particular, a restricted token that at the same time has the
perm_manage_tokens
permission is able to free itself from its
restrictions (see Token Field Reference).
Token Policy Field Reference¶
A JSON object representing a token policy has the following structure:
{
"id": "7aed3f71-bc81-4f7e-90ae-8f0df0d1c211",
"domain": "example.com",
"subname": null,
"type": null,
"perm_write": true
}
Field details:
id
- Access mode:
read-only
- Type:
UUID
Token policy ID, used for identification only (e.g. when modifying a policy). (Not to be confused with the token’s ID.)
domain
- Access mode:
read, write
- Type:
string or
null
Domain name to which the policy applies.
null
for the default policy.subname
- Access mode:
read, write
- Type:
string or
null
Subname to which the policy applies.
null
for the default policy.type
- Access mode:
read, write
- Type:
string or
null
Record type to which the policy applies.
null
for the default policy.perm_write
- Access mode:
read, write
- Type:
boolean
Indicates write permission for the RRset specified by (
domain
,subname
,type
) when using the general RRset management or dynDNS interface. Defaults tofalse
.
Token Policy Management¶
Token Policies are managed using the policies/rrsets/
endpoint under the
token’s URL.
Usage of this endpoint requires that the request’s authorization token has the
perm_manage_tokens
flag.
Semantics, input validation, and error handling follow the same style as the
rest of the API, so is not documented in detail here.
For example, to retrieve a list of policies for a given token, issue a GET
request as follows:
curl -X GET https://desec.io/api/v1/auth/tokens/{id}/policies/rrsets/ \
--header "Authorization: Token mu4W4MHuSc0Hy-GD1h_dnKuZBond"
The server will respond with a list of token policy objects.
To create the default policy, send a request like:
curl -X POST https://desec.io/api/v1/auth/tokens/{id}/policies/rrsets/ \
--header "Authorization: Token mu4W4MHuSc0Hy-GD1h_dnKuZBond" \
--header "Content-Type: application/json" --data @- <<< \
'{"domain": null, "subname": null, "type": null}'
This will create a default policy. If the perm_write
permission flag is
not given, it is assumed to be false
.
As an example, let’s create a policy that only allows manipulating all A records for a specific domain:
curl -X POST https://desec.io/api/v1/auth/tokens/{id}/policies/rrsets/ \
--header "Authorization: Token mu4W4MHuSc0Hy-GD1h_dnKuZBond" \
--header "Content-Type: application/json" --data @- <<< \
'{"domain": "example.dedyn.io", "subname": null, "type": "A", "perm_write": true}'
Tip: To authorize dual-stack dynDNS updates, create two policies (for access to the A and AAAA RRsets, respectively).
You can retrieve (GET
), update (PATCH
, PUT
), and remove
(DELETE
) policies by appending their id
to the endpoint:
curl -X DELETE https://desec.io/api/v1/auth/tokens/{token.id}/policies/rrsets/{policy.id}/ \
--header "Authorization: Token mu4W4MHuSc0Hy-GD1h_dnKuZBond"
When modifying or deleting policies, the API enforces the default policy’s primacy: You cannot create specific policies without first creating a default policy, and you cannot remove a default policy when other policies are still in place.
During deletion of tokens, users, or domains, policies are cleaned up automatically.
Security Considerations¶
This section is for purely informational. Token length and encoding may change in the future.
Any token secret is generated from 164 bits of randomness at the server and stored in hashed format (PBKDF2-HMAC-SHA256). Guessing the secret correctly or reversing the hash is considered practically impossible.
The token’s secret value is represented by 28 characters using a URL-safe
base58 encoding.
It is based on a case-sensitive alphanumeric alphabet excluding the characters
lIO0
(hence comprising only the symbols a-k
, m-z
, A-H
,
J-N
, P-Z
, and 1-9
).
This encoding is optimized for maximum clarity and usability:
Exclusion of certain letters minimizes visual ambiguity, while the restriction
to alphanumeric symbols allows easy selection (double-click) and input, and
helps avoid line breaks during display.
Before December 2022, tokens encoded a 21-byte secret using a URL-safe variant
of base64 encoding, comprising of the 28 characters A-Z
, a-z
, 0-9
,
-
, and _
.
(Base64 padding was not needed as the string length is a multiple of 4.)
Before September 2018, tokens encoded a 20-byte secret using 40 hexadecimal characters.
Legacy tokens are not issued anymore, but remain valid until invalidated by the user.