Skip to main content
Version: 1.0 RC1 (Latest)

Authentication

Nobody should mess around with your private jewelry. When Document Access Control or Node Access Control is enabled on an instance, all requests acting on restricted resources must be authenticated with an identity's private key. The authentication looks different depending on the tool originating the request.

note

The examples on this page use secp256k1 keys, but the flow is similar for ed25519 keys.

CLI commands

To authenticate with an identity in CLI commands, provide the actor's PrivateKey to the --identity flag.

Example – Authenticated query
defradb client query \
--identity b17a7b973f629b900cf23654db9c4be935f90281707dd3e2cd7a56bdd2c1bf4f \
'{ Book { title } }'

HTTP requests

HTTP requests are authenticated with an extra header:

Authorization: Bearer <jwtToken>

where <jwtToken> is a JSON Web Token, composed of header, payload, and signature parts, each separated by a dot .:

JWT token structure

<header>.<payload>.<signature>

Example – JWT token

eyJhbGciOiJFUzI1NksiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOlsiMTI3LjAuMC4xOjkxODEiXSwiZXhwIjoxNzgxNTk5MzAyLCJpYXQiOjE3ODE1OTg0MDIsImlzcyI6ImRpZDprZXk6ejdyOG9xVWNTbTZ4d3d4ZnBCWjVSNkNXUWlQUm5ZcFhvdXdnZVhrYldnVmNXQkYxOVFEbmRCQld6Z0hjdnZIaGFVZTdxY1R6N2F5SlZYa3NORDM3cnZWN0dBVUF2Iiwia2V5X3R5cGUiOiJzZWNwMjU2azEiLCJuYmYiOjE3ODE1OTg0MDIsInN1YiI6IjAzNjNmMjI0YmZkZGI2NDFiZDBjZDRiNTQwOWJjOTIxYzQwNTQ2MDcyN2Y4NjRmNmRiYTMzZGE1ZGQ3YjA2MWJjZiJ9.n9QbkwnpvcGOBo4aRRnOP-gANBQNAtNx3y428On3fhNxSh42Al1pNm5m9DvyTTjYOS6ZIwK2ECm6pxqwOAGtcg

JWT tokens are not scoped to specific actions, so anybody with a valid token can run any action that the signing identity has permission to execute.

HTTP requests carrying an invalid JWT token result in a 403 Forbidden HTTP status code.

Header

Example – Header
{
"alg": "HS256K",
"typ": "JWT"
}

Valid values for alg are: HS256K, EdDSA. The algorithm must match the identity key type. Most tools implicitly craft the header object for you basing on the signing algorithm.

Payload

Example – Payload
{
"sub": "0363f224bfddb641bd0cd4b5409bc921c405460727f864f6dba33da5dd7b061bcf",
"aud": "localhost:9181",
"exp": 1781536870,
"nbf": 1781532870,
"key_type": "secp256k1"
}
  • sub – Identity's PublicKey, in hex format.
  • aud – Hostname(s) of the DefraDB HTTP API the token is allowed with. String or list of strings.
  • exp – Token expiration UNIX timestamp.
  • nbfnot-before UNIX timestamp (token invalid before that time).
  • key_type – The key type must match the identity key type. Valid values: secp256k1, ed25519.
note

For policies hosted on SourceHub, more fields are required in the payload:

  • iss – Identity's DID key.
  • iat – Current UNIX timestamp.
  • authorized_account – SourceHub address of the account signing transactions on your behalf (a Bech32 address with a specific SourceHub prefix).

Signature

The JWT token is signed with the PrivateKey corresponding to the PublicKey specified in the payload sub field.

Example – PrivateKey
b17a7b973f629b900cf23654db9c4be935f90281707dd3e2cd7a56bdd2c1bf4f

Generate tokens programmatically

This example uses the PyJWT and cryptography libraries. The function jwt.encode() produces a JWT token; however, because that requires a PEM-encoded version of the private key, the function ec.derive_private_key() reads the key into an elliptic curve object and the method .private_bytes() outputs the private key in the requested bytes, PEM-encoded format.

import jwt
import time

from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.serialization import NoEncryption, PrivateFormat
from cryptography.hazmat.primitives.serialization import Encoding

pub_hex = '0363f224bfddb641bd0cd4b5409bc921c405460727f864f6dba33da5dd7b061bcf'
priv_hex = 'b17a7b973f629b900cf23654db9c4be935f90281707dd3e2cd7a56bdd2c1bf4f'
now = int(time.time())

payload = {
"sub": pub_hex,
"aud": ["127.0.0.1:9181", "localhost:9181"],
"exp": now + 60*60, # valid for an hour
"nbf": now - 30,
"key_type": "secp256k1",
}

# Convert hex-encoded private key into PEM-encoded bytes
priv_int = int(priv_hex, 16)
priv_ec = ec.derive_private_key(priv_int, ec.SECP256K1())
priv_bytes = priv_ec.private_bytes(
encoding=Encoding.PEM, format=PrivateFormat.PKCS8, encryption_algorithm=NoEncryption()
)

token = jwt.encode(payload, priv_bytes, algorithm='ES256K')
print('token:', token)