Users and Environments
Howto create new users? Howto modify them?
▽Dec. 22, 2020|Bernhard Kauer
developerdraft
1. Environments
The users are the top-level objects of the Puzzle API. They are the containers for all currency accounts, which itself keep the transactions and their attachments.
Each user object resides inside an environment. Currently two of them
are defined. First the real
environment where normal money
can be transfered between Puzzle accounts and outside Puzzle through the
SEPA system. Secondly, the sandbox
environment. It can be
use for playing with the API and implementing use-cases where no real
money is required.
The assignment of a user to an environment is done at creation time and cannot be changed afterwards.
1.1 The differences between the environments
Placing a user inside the sandbox
has the following
advantages compared to the real
environment:
- no identification is required - one can start immediately
- a credit line is possible
- more currencies are enabled
- new features will be made available in the
sandbox
first
However, a few operations are not possible inside a
sandbox
:
- sending money to external banks
- testing the identification methods
2. Creating a new User
Every other API call needs an existing user object. Creating one is therefore often the first task one has to perform. In this section we therefore show this process step-by-step to ease the implementation of this basic functionality.
To create a new user, send a POST request to the
/pzl
endpoint.
$ curl -s -X POST https://$HOST/pzl
{"reason": "need JSON body"}
The content-type must be application/json
.
$ curl -s -X POST -H "Content-type: application/json" https://$HOST/pzl
{"reason": "invalid JSON"}
And the body has to be valid JSON.
$ echo -n '{}' | curl -s -T - -X POST -H "Content-type: application/json" https://$HOST/pzl
{"reason": "invalid environment"}
An environment must be given where the user should reside.
$ echo -n '{"env": "sandbox"}' | curl -T - -X POST -s -H "Content-type: application/json" https://$HOST/pzl
{"reason": "invalid keytype"}
The keytype must be ed25519
. Other keytypes are not
supported yet.
$ echo -n '{"env": "sandbox", "keytype": "ed25519"}' | curl -T - -X POST -s -H "Content-type: application/json" https://$HOST/pzl
{"reason": "invalid pubkey"}
The public key for ed25519 is 32-bytes long and is transfered
base64-encoded
inside the JSON. The URL-safe variant of the
encoding is prefered.
$ echo -n '{"env": "sandbox", "keytype":"ed25519", "pubkey":"TtMvY7818O7vyyXyii4fvchzrig1ZxsMlGD18S5FVqg="}' | curl -T - -X POST -s -H "Content-type: application/json" https://$HOST/pzl
{"reason": "authorization missing"}
An authorization header for the puzzle authentication scheme must be provided. The signature is validated against the public key that is send in the body. A full trace therefore looks like:
$ puzzle-client -d -d user 2>&1
< POST /pzl HTTP/2
< authorization: pzl time=1608641178+60,sig=TRplU9GOA2yHTtQkSy-cG1w5RTs7u9X_EwUcBBUz1EF-CK9DvhqICTF_s7WThgdc6Actf7AfxP-SNQ4JvxtxDA
< content-type: application/json
<
< {"env":"sandbox","keytype":"ed25519","pubkey":"lml7WeRunbqRp0VTeAc68YLnz6KKVHb_WoYP1GJGBwM="}
> HTTP/2 200
> etag: g8scu7crfIr2mCU8dL41XC0EiCMkJ9fE27py_DfjSzrQ
> content-type: application/json
> cache-control: no-cache
> location: /pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN
> date: Tue, 22 Dec 2020 12:46:18 GMT
> content-length: 783
>
>
> [{"type": "user",
> "current": "/pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN",
> "canonical": "/pzl/s3e8.g8scu7crfIr2mCU8dL41XC0EiCMkJ9fE27py_DfjSzrQ",
> "event": {"date": 1608641178.51564,
> "author": "puzzle-service api <318637@n18-1>",
> "category": "user",
> "name": "s3e8",
> "operation": "init"},
> "children": {"accounts": "g4Krr2gT1hqmVBirI5tCGY-9f3yULCRpIrJhd54Pga8G",
> "auths": "g2AwJgwSUC0pikuVXAv70pct7sWdVFP-cdRz6WBKh8HP",
> "info": "gzKZK5RbBgOaiYlaWdq395VMFFBa6p6h9IL5QBt6O6Yq"}},
> {"type": "user-info",
> "current": "/pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN/info",
> "canonical": "/pzl/s3e8/info.gzKZK5RbBgOaiYlaWdq395VMFFBa6p6h9IL5QBt6O6Yq",
> "properties": {"api": "1 20200304",
> "current": "AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN",
> "env": "sandbox",
> "id": "s3e8",
> "name": "Spoon Cloud sandbox"}}]
>
/pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN
The location header in the reply is the current path of the newly
created user object. The object itself as well as the
user-info
is returned to get instant feedback before a
potential asynchronous synchronization operation succeeds.
2.1 Duplicate Keys
Since the server cannot verify the actual strength of a private key, it is up to the client to submit only secure public keys. Deriving the private key from a user-provided password is not sufficient. The key must be generated from a cryptographically secure random number generator.
However, the server will detect duplicate and blacklisted keys. A 400 error is returned in this case. The corresponding reply body will be:
{"reason": "duplicate key"}
This error may also occur if an interrupted operation is retried, as the key might already be recorded by the backend even if the client has not received a successfull reply.
2.2 Enumerating all Users
Existing users cannot be enumerated through the API for security
reasons. The client must store the location and the private keys
securely. Recovery through the API is not possible if this information
is lost. It is therefore advisable to use a secondary auth
for backup purposes.
In the future there will be alternative recovery options for
real
accounts involving a potentially expensive
re-identification of the user.
2.3 Deleting a User
There is no way to delete a user within the API. Owners and transactions might have to be kept for several years for legal reasons.
However, inactive users will be garbage collected and archieved after
some time. To speedup this process, delete all auth
objects
so that external access is not possible anymore.
3. User Object
3.1 Retrieving the current version
The current version can be retrieved via a GET
request
to the current URL of the user object. An authorization header for the
puzzle authentication scheme
must be provided.
The signature in the following example is validated against the default public key that was given to the server during user creation. The return body is formated in JSON.
$ puzzle-client -d get /pzl/s3e8 2>&1
< GET /pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN HTTP/2
< authorization: pzl time=1608641178+60,sig=fQ2dWD_xll50RdceKba83PKR59clcTUpbx8YmSniVUxCd9sNeDPt2ZPE62iZX9Fa65wnDRG1nQWecW8u8JabBA
<
> HTTP/2 200
> cache-control: no-cache
> content-length: 473
> content-type: application/json
> date: Tue, 22 Dec 2020 12:46:18 GMT
> etag: g8scu7crfIr2mCU8dL41XC0EiCMkJ9fE27py_DfjSzrQ
>
> {
> "canonical": "/pzl/s3e8.g8scu7crfIr2mCU8dL41XC0EiCMkJ9fE27py_DfjSzrQ",
> "children": {
> "accounts": "g4Krr2gT1hqmVBirI5tCGY-9f3yULCRpIrJhd54Pga8G",
> "auths": "g2AwJgwSUC0pikuVXAv70pct7sWdVFP-cdRz6WBKh8HP",
> "info": "gzKZK5RbBgOaiYlaWdq395VMFFBa6p6h9IL5QBt6O6Yq"
> },
> "current": "/pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN",
> "event": {
> "author": "puzzle-service api <318637@n18-1>",
> "category": "user",
> "date": 1608641178.51564,
> "name": "s3e8",
> "operation": "init"
> },
> "type": "user"
> }
The canonical
attribute defines a path to this version
that never changes. It can be seen as the version-number of the object.
Requesting the canonical path returns exactly the very same object in
the future. This allows one to refetch objects that where dropped at the
client.
The prev
attribute links to the previous version of this
object. This enables backward iteration through the different versions.
The prev
field is not present on the very first
version.
3.2 Conditional Requests
The GET
and HEAD
request return the
etag
of the object. This is a hash over the object or
sub-object and guaranteed to be unique over time.
$ puzzle-client head /pzl/s3e8 | grep etag | cut -c 3-
etag: g8scu7crfIr2mCU8dL41XC0EiCMkJ9fE27py_DfjSzrQ
This can be used with a if-none-match
header to detect
whether the current state of an object was modifed or not. The server
returns a 304 error if the etag
is still
current.
$ puzzle-client -d head -H "if-none-match: $(puzzle-client head /pzl/s3e8 | grep etag | cut -c 9-)" /pzl/s3e8 2>&1
< HEAD /pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN HTTP/2
< authorization: pzl time=1608641179+60,sig=PgEx7SVxbI1K1RZ7XRlftub6SgrneU1La51BfWjy1heTTAm920DypUjtAkBnRKaYqhwwTZlEJEpdMBky3VA4DQ
< if-none-match: g8scu7crfIr2mCU8dL41XC0EiCMkJ9fE27py_DfjSzrQ
<
> HTTP/2 304
> content-length: 0
> date: Tue, 22 Dec 2020 12:46:19 GMT
>
It may also be used together with a prefer
header to
implement long-polling.
3.3 Events
The event object inside the user looks like:
{
"author": "puzzle-service api <267976@n18-1>",
"category": "user",
"date": 1608582480.928915,
"name": "s:3e8",
"operation": "merge",
"subcategory": "account",
"versions": "0-0"
}
The example shows a merge
of certain
versions
from the account s:3e8
into this user
object. The author
field reveals the backend service that
created this version. This is usefull for debugging purposes.
The date
of this version is given as Unix time (UTC
seconds since 1970) in micro-second resolution. The accuracy of this
timestamp might be a lot lower due to clock-drifts and process
interruptions on the server.
The category
and subcategory
specify where
this event comes from.
Examples for operation
done through the API are:
init
- for initializing the objectcreate
- for creating new child objectsupdate
- for modifying a childdelete
- for deleting a child
The name
gives a hint where this operation
happenend.
4. User Information Object
The user-info
object details the information the backend
has about a certain user. To retrieve it, request the info
child from the user.
$ puzzle-client -q get /pzl/s3e8/info
{
"canonical":"/pzl/s3e8/info.gzKZK5RbBgOaiYlaWdq395VMFFBa6p6h9IL5QBt6O6Yq",
"current":"/pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN/info",
"properties":{
"api":"1 20200304",
"current":"AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN",
"env":"sandbox",
"id":"s3e8",
"name":"Spoon Cloud sandbox"
},
"type":"user-info"
}
These are the properties for the user-info
object:
- api - version number for the API
- current - the TAG to be used in all current links
- env - the environment the user is in
- id - the id of the user
- name - a name for the user
- description - a human-readable description
- icon - the name of an icon to be shown in the App
4.1 Modifications
Certain properties of the user-info
object are writable.
An OPTIONS call reveals that currently description
,
icon
and name
fall in this class. This list
will be extended in the future.
$ puzzle-client -q options /pzl/s3e8/info
{
"optional":[
"description",
"icon",
"name"
]
}
Modifications are performed with a POST request:
echo "info description=$(date +%s)" | puzzle-client -d update /pzl/s3e8 2>&1
< POST /pzl/s3e8.AJjrTPfvyraFORT1SPnPOOJygikA9Qa0/info HTTP/2
< authorization: pzl time=1583943032+60,sig=MYLpiaV-s4gaFUWiuM186aFnSxq_ZRbaIQm7gwS6TYbeO46c576YZEYYN8WDak-pzwo_HktYd0vgDyRYa34FAQ
< content-type: application/json
<
< {"description":"1583943032"}
> HTTP/2 200
> content-length: 413
> content-type: application/json
> date: Wed, 11 Mar 2020 16:10:32 GMT
> etag: g3AOF-hhII3GQBbm2_QS9KmpliNnEboM_Vicr9jUtPKy
>
> {
> "canonical": "/pzl/s3e8/info.g3AOF-hhII3GQBbm2_QS9KmpliNnEboM_Vicr9jUtPKy",
> "current": "/pzl/s3e8.AJjrTPfvyraFORT1SPnPOOJygikA9Qa0/info",
> "prev": "/pzl/s3e8.g23_JGQ6GIeh8u5D4AxLRYiGAg8X0fD7tgFF2jnM3A_-/info",
> "properties": {
> "api": "1 20200304",
> "current": "AJjrTPfvyraFORT1SPnPOOJygikA9Qa0",
> "description": "1583943032",
> "env": "sandbox",
> "id": "s3e8",
> "name": "Sandbox 3e8"
> },
> "type": "user-info",
> "version": 7
> }
This either returns a 200 and the new object or a 204 if no modification was performed.
$ echo "info foo=bar" | puzzle-client -q update /pzl/s3e8
204 /pzl/s3e8/info
5. Authorization Objects
The authorization objects contain all data needed to authorize
requests. Most important are the public key for the puzzle authentication scheme.
Multiple auth
objects can be created per user to enable
multi-device access and for backup purposes.
We have implement a fine-grained access-model, that supports read-only and time-limited access.
5.1 Listing all Auths
All authorization objects of a user can be listed with a
GET
request.
$ puzzle-client -q get /pzl/s3e8/auths
{
"canonical":"/pzl/s3e8/auths.g2AwJgwSUC0pikuVXAv70pct7sWdVFP-cdRz6WBKh8HP",
"children":{
"x1":"g2mMkX3ksrvl-MO3efFNxtvSrkYCmpLDZyXrjIIAhOir"
},
"current":"/pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN/auths",
"type":"auth-list"
}
The children
lists the available authorization objects
with their etag
.
5.2 Retrival
A authorization object can be retrieved by combining its name with
the cannonical
or current
path of the
auth-list
.
$ puzzle-client -q get /pzl/s3e8/auths/x1
{
"canonical":"/pzl/s3e8/auths/x1.g2mMkX3ksrvl-MO3efFNxtvSrkYCmpLDZyXrjIIAhOir",
"current":"/pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN/auths/x1",
"properties":{
"description":"default",
"keytype":"ed25519",
"name":"x1",
"policies":[
{
"until":1671540378
}
],
"pubkey":"lml7WeRunbqRp0VTeAc68YLnz6KKVHb_WoYP1GJGBwM="
},
"type":"auth"
}
The object keeps the pubkey
and type
as
well as a description
to let the user distinguish different
authorizations. The default policies
grants full access
until
the object is valid.
5.3 Creation
To create a new auth
object, one sends a new public key
to the auth-list
. An OPTIONS call to the URL reveals the
supported parameters.
$ puzzle-client -q options /pzl/s3e8/auths
{
"choice":{
"keytype":[
"ed25519"
]
},
"mandatory":[
"keytype",
"pubkey"
],
"optional":[
"description",
"policies"
]
}
Both keytype
and pubkey
must be given. A
human-readable description is optional.
The creation is done throught the POST method.
$ puzzle-client -d -d auth /pzl/s3e8 2>&1
< POST /pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN/auths HTTP/2
< authorization: pzl time=1608641180+60,sig=E95mGNgvt0ghnTKYpb0dmA_Uk3IHAO2NpCuMHCGCqfC7safVc_khQvhltbZ9Ohfk5dqIBNCvC5JxmljniGJ5CQ
< content-type: application/json
<
< {"description":"default","keytype":"ed25519","pubkey":"Kvmfyj78jlsQp08GJ3NrzXdBybOuz0osMlWctwymQms="}
> HTTP/2 200
> content-type: application/json
> cache-control: no-cache
> location: /pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN/auths/x2
> date: Tue, 22 Dec 2020 12:46:20 GMT
> content-length: 709
>
>
> [{"type": "auth-list",
> "current": "/pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN/auths",
> "canonical": "/pzl/s3e8/auths.gwPhGzUedeMhKjp0rsuxm8ikqcHBwDLrCtsb83dZzGGa",
> "prev": "/pzl/s3e8.g8scu7crfIr2mCU8dL41XC0EiCMkJ9fE27py_DfjSzrQ/auths",
> "version": 1,
> "children": {"x1": "g2mMkX3ksrvl-MO3efFNxtvSrkYCmpLDZyXrjIIAhOir",
> "x2": "gwfMOq4MZP-PsUKzpVzaah8Nyd6ItxVsAciAszu7Elg7"}},
> {"type": "auth",
> "current": "/pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN/auths/x2",
> "canonical": "/pzl/s3e8/auths/x2.gwfMOq4MZP-PsUKzpVzaah8Nyd6ItxVsAciAszu7Elg7",
> "properties": {"description": "default",
> "keytype": "ed25519",
> "name": "x2",
> "policies": [{"until": 1671540380}],
> "pubkey": "Kvmfyj78jlsQp08GJ3NrzXdBybOuz0osMlWctwymQms="}}]
>
/pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN/auths/x2
The location header in the reply is the current path of the newly created authorization object.
5.4 Modification
An existing auth
object can be modified. An OPTIONS call
to the URL reveals the supported parameters.
$ puzzle-client -q options /pzl/s3e8/auths/x1
{
"choice":{
"keytype":[
"ed25519"
]
},
"optional":[
"description",
[
"keytype",
"pubkey"
],
"policies"
]
}
This means description
and the public key are both
optional. If the later is changed both keytype
and
pubkey
must be provided.
Unknown fields and non-modifying updates are ignored.
$ echo 'auths/x1 description=default foo=bar' | puzzle-client -q update /pzl/s3e8
204 /pzl/s3e8/auths/x1
Updates are better performed on the canonical URL, as this allows to detect race conditions. Any succesfull modification returns the new object version.
$ echo "$(puzzle-client -q get /pzl/s3e8/auths/x1 | grep canonical | cut -d'"' -f 4) description=first" | puzzle-client -d update / 2>&1
< POST /pzl/s3e8/auths/x1.g2mMkX3ksrvl-MO3efFNxtvSrkYCmpLDZyXrjIIAhOir HTTP/2
< authorization: pzl time=1608641180+60,key=x2,sig=6U-gc1_l7-sy7R-STeGAo0v8q2BV0Jh5LuEdOHZrOuntSQePfx3gjliPare3IXqMOrNAyeM3BxQWGDVEOOLCAg
< content-type: application/json
<
< {"description":"first"}
> HTTP/2 200
> content-length: 501
> content-type: application/json
> date: Tue, 22 Dec 2020 12:46:20 GMT
> etag: g_L3O1knFl2u9xMQVY54DfojgRQZusPMbAx97kiUouKq
>
> {
> "ancient": "/pzl/s3e8.g8scu7crfIr2mCU8dL41XC0EiCMkJ9fE27py_DfjSzrQ/auths/x1",
> "canonical": "/pzl/s3e8/auths/x1.g_L3O1knFl2u9xMQVY54DfojgRQZusPMbAx97kiUouKq",
> "current": "/pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN/auths/x1",
> "prev": "/pzl/s3e8.g-Rf0fttdUnl88btdmxnBo0aSiFneLsRoJ-1y71XNHBI/auths/x1",
> "properties": {
> "description": "first",
> "keytype": "ed25519",
> "name": "x1",
> "policies": [
> {
> "until": 1671540378
> }
> ],
> "pubkey": "lml7WeRunbqRp0VTeAc68YLnz6KKVHb_WoYP1GJGBwM="
> },
> "type": "auth",
> "version": 2
> }
Performing the very same operation on an older version leads to a
412 precondition failed
as the given URL is not current
anymore.
$ echo "$(puzzle-client -q get /pzl/s3e8/auths/x1 | grep prev | cut -d'"' -f 4) description=second" | puzzle-client update /
412 /pzl/s3e8.g-Rf0fttdUnl88btdmxnBo0aSiFneLsRoJ-1y71XNHBI/auths/x1
In this case one has to refetch the current state of the
auth
object before performing the update again.
5.5 Rolling Key Updates
Modifying a key directly is tricky to implement at the client, as the reply might not reach the client due to limited internet availability. If this happens the client may only guess which key the server will accept in the future. We therefore support a rolling update scheme where the old key is retained until the new key is confirmed.
The first step in the process is to register a new key:
$ puzzle-client -d auth --postfix=/auths/x1 /pzl/s3e8 2>&1
< POST /pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN/auths/x1 HTTP/2
< authorization: pzl time=1608641181+60,key=x2,sig=OuwAryoQozSXUdMGdhyYXWk-AOUnNKDvhUMGafqcOkO2EnDMpHIc_KPo9uTnuCILk6hvkGsMu1EJ6bm8J9dUBA
< content-type: application/json
<
< {"description":"default","keytype":"ed25519","pubkey":"I30_pyo0YBFqAr-NAEI97ihxcQeb3DSbDFUEsWANDK0="}
{"type": "auth",
"current": "/pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN/auths/x1",
"canonical": "/pzl/s3e8/auths/x1.gxIYL3PVOB3MZoqCazjKuWM_FB7cLvtpMl9gF4pNNFp_",
"properties": {"description": "default",
"keytype": "ed25519",
"keytype2": "ed25519",
"name": "x1",
"policies": [{"until": 1671540378}],
"pubkey": "lml7WeRunbqRp0VTeAc68YLnz6KKVHb_WoYP1GJGBwM=",
"pubkey2": "I30_pyo0YBFqAr-NAEI97ihxcQeb3DSbDFUEsWANDK0="},
"prev": "/pzl/s3e8.g6Wgeojhq9jl9WL_9IGhSC0hlHr-F6bVmT3lMIkmg5UL/auths/x1",
"version": 3,
"ancient": "/pzl/s3e8.g8scu7crfIr2mCU8dL41XC0EiCMkJ9fE27py_DfjSzrQ/auths/x1"}
This installs a pubkey2
of keytype2
that
can be used in parallel to the previous key. To confirm the new key,
issue the operation with the very same public key again.
$ echo -n x1 keytype=ed25519 pubkey=$(puzzle-client -q get /pzl/s3e8/auths/x1 | grep pubkey2 | cut -d'"' -f4) | puzzle-client -d update /pzl/s3e8/auths 2>&1
< POST /pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN/auths/x1 HTTP/2
< authorization: pzl time=1608641181+60,key=x2,sig=rNrjiHlBx2sDjpakyLlMqLUEpHlobSjwxbDJDNhsY0zZdYjOfvpNlgDIFycbFnOQjlfBdXTz2rFKgrJvu42PCA
< content-type: application/json
<
< {"keytype":"ed25519","pubkey":"I30_pyo0YBFqAr-NAEI97ihxcQeb3DSbDFUEsWANDK0="}
> HTTP/2 200
> content-length: 503
> content-type: application/json
> date: Tue, 22 Dec 2020 12:46:21 GMT
> etag: g6UI_ELkHDLxCEM84k-w_v2TIltwIKfY0yV1rp_NTa1A
>
> {
> "ancient": "/pzl/s3e8.g6Wgeojhq9jl9WL_9IGhSC0hlHr-F6bVmT3lMIkmg5UL/auths/x1",
> "canonical": "/pzl/s3e8/auths/x1.g6UI_ELkHDLxCEM84k-w_v2TIltwIKfY0yV1rp_NTa1A",
> "current": "/pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN/auths/x1",
> "prev": "/pzl/s3e8.g6tClDljNyf4UthkNwXRiNo0UTQHYI3ceid9gyeXIRQV/auths/x1",
> "properties": {
> "description": "default",
> "keytype": "ed25519",
> "name": "x1",
> "policies": [
> {
> "until": 1671540378
> }
> ],
> "pubkey": "I30_pyo0YBFqAr-NAEI97ihxcQeb3DSbDFUEsWANDK0="
> },
> "type": "auth",
> "version": 4
> }
One may also drop the new key by sending the older one instead. To
avoid race conditions, one should use the canonical
path
for both operations.
5.6 Access Control Policies
Fine-grained access control is possible by defining a policy that
decides which operations are allowed for a given auth
object. This policy is checked only for requests with valid signatures
to avoid information leaks. The policy itself is a list of entries that
can be specified when creating or modifying an auth
object.
At least one of the entries must match for any request.
The fields of the entries are as follows:
- until - a UTC timestamp until the entry is valid
- method - the HTTP Methods allowed
- prefix - the prefixes of the allowed requests
The until field is always set. This enables timely replacement of unecessary rights and deprecated cryptograpic methods. If no expiration date is given, the maximum duration (currently two years) is choosen.
One can set a read-only policy by allowing only the GET method:
$ echo -n 'x2 policies=[{"method":"GET"}]' | puzzle-client update /pzl/s3e8/auths
{
"canonical":"/pzl/s3e8/auths/x2.g2vqNv01IHzpQZMGitFNXaMw0MhmT93lvi0RgcCEwzm5",
"current":"/pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN/auths/x2",
"prev":"/pzl/s3e8.g0w5tKJ80gb-Uv3XxXhyv4gGtEsCbYoYuJOYN0LzhPQr/auths/x2",
"properties":{
"description":"default",
"keytype":"ed25519",
"name":"x2",
"policies":[
{
"method":"GET",
"until":1671540381
}
],
"pubkey":"Kvmfyj78jlsQp08GJ3NrzXdBybOuz0osMlWctwymQms="
},
"type":"auth",
"version":5
}
If the policy check fails on any method, a 401 error is returned.
$ echo -n 'x2 policies=[{"method":"GET"}]' | puzzle-client --keyname=x2 update /pzl/s3e8/auths
401 /pzl/s3e8/auths/x2
5.7 Deletion
An existing auth
object can be deleted.
$ puzzle-client --keyname=x1 -q delete /pzl/s3e8/auths/x2
{
"ancient":"/pzl/s3e8.g0w5tKJ80gb-Uv3XxXhyv4gGtEsCbYoYuJOYN0LzhPQr/auths",
"canonical":"/pzl/s3e8/auths.g3-GqC0y53_LQ76Yut8dOBvrZADUvSlZZy2fxjO8Urhm",
"children":{
"x1":"g6UI_ELkHDLxCEM84k-w_v2TIltwIKfY0yV1rp_NTa1A"
},
"current":"/pzl/s3e8.AGPyrPuKeB_kFgCB2b-uL35EqLKrwZyN/auths",
"prev":"/pzl/s3e8.g5i9_Yu0nELFyKaw0exCFIKU9FJ2Q1ybVfeH8ihwhnxa/auths",
"type":"auth-list",
"version":6
}
Further access with this key is prohibited.
$ puzzle-client -q --keyname=x2 get /pzl/s3e8 2>&1
{
"reason":"key not found"
}
6. Further Questions
6.1 Where can I try this API? Is there a demo instance of Puzzle?
There is no special demo instance of Puzzle. For testing purposes
create a user inside the sandbox
environment.
6.2 How do I know in which environment a user resides?
The user and account names start with a different prefix. A user
named s3f5
would be in the sandbox.