例

詳しい例

ネットワークを流れるもの、実際のバイト列で。手書きのものはなく、リポジトリが検証するテストベクターと例から読み込んでいます。

鍵・トークン・名前は架空のテスト値です(鍵はRFC 8032が公開しているテスト鍵)。本物ではありません。

署名付きリクエストをバイト単位で

鍵でペアリングした端末は、トークンを載せる全リクエストに署名します。サーバーはリクエストから署名ベースを再構成し、トークンに紐付けた鍵で署名を検証します。

送信されるリクエスト

GET /api/lantern/v1/apps?page_size=50 HTTP/1.1
Host: shelf.example.org
Authorization: Bearer et_c8V1nQ0xYbExampleVectorToken0000000000
Signature-Input: lantern=("@method" "@target-uri" "authorization");created=1793345400;nonce="tQ0Vb3Yt7sXx2c1mZ8kq4A";keyid="If4x36FUomFia_hUBG_SJxt77UtqvkWqWId-9H-XIbk";alg="ed25519"
Signature: lantern=:M8AuwRfGqDSUYUefbsIOlmFKxvi+6HnHv0pvbD22n/lrJqHvPcvYThUUCqK+6C63s9nTQPThdrTfM9yFwt6aBA==:

端末が署名する署名ベース

"@method": GET
"@target-uri": https://shelf.example.org/api/lantern/v1/apps?page_size=50
"authorization": Bearer et_c8V1nQ0xYbExampleVectorToken0000000000
"@signature-params": ("@method" "@target-uri" "authorization");created=1793345400;nonce="tQ0Vb3Yt7sXx2c1mZ8kq4A";keyid="If4x36FUomFia_hUBG_SJxt77UtqvkWqWId-9H-XIbk";alg="ed25519"

端末の鍵

private key (seed): 9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60
public key:         11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo=
keyid:              If4x36FUomFia_hUBG_SJxt77UtqvkWqWId-9H-XIbk
short fingerprint:  21FE 31DF A154 A261

署名のない同じリクエスト

Authorization: Bearer et_c8V1nQ0xYbExampleVectorToken0000000000

→ 401 · signature_required

§ 5.4 · vectors/signatures.json

コードからトークンまでのペアリング

端末はコードを要求して表示し、所有者はサーバーにサインインした別の端末で承認します。端末はトークンが一度だけ渡されるまでポーリングします。

  1. 1. 端末がペアリングを要求

    POST /api/lantern/v1/pairing HTTP/1.1
    Host: shelf.example.org
    Content-Type: application/json
    
    {
      "schema": 1,
      "device": "Lea's Switch",
      "scopes": [
        "library",
        "saves"
      ],
      "key": {
        "alg": "ed25519",
        "public_key": "11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo="
      }
    }
  2. 2. サーバーがコードを返す

    HTTP/1.1 200 OK
    Content-Type: application/json
    
    {
      "schema": 1,
      "code": "KQ4M-7TXD",
      "verify": "https://shelf.example.org/pair",
      "verify_complete": "https://shelf.example.org/pair?code=KQ4M-7TXD",
      "poll": "/api/lantern/v1/pairing/p_4Fh2",
      "interval": 5,
      "expires": 600
    }
  3. 3. 所有者が承認し、端末がポーリング

    GET /api/lantern/v1/pairing/p_4Fh2 HTTP/1.1
    Host: shelf.example.org
    Signature-Input: lantern=("@method" "@target-uri");created=…;nonce="…";keyid="…";alg="ed25519"
    Signature: lantern=:…:
  4. 4. トークン(一度だけ)

    HTTP/1.1 200 OK
    Content-Type: application/json
    
    {
      "schema": 1,
      "token": "et_c8V1nQ0xYb",
      "scopes": [
        "library",
        "saves"
      ],
      "bound": true,
      "rating_cap": {
        "system": "PEGI",
        "rating": "12"
      }
    }

§ 5.2 · examples/v1/

ピア向けの許可証

サーバーは「クライアントが1つのファイルを読める」という短い声明に署名します。そのファイルを持つピアは、誰にも問い合わせず、サーバーの公開鍵で検証します。

サーバーが署名するもの(JSON、キーはこの順、空白なし)

{"exp":1793346000,"purpose":"lantern-grant-1","sha256":"3a7bd3e2b4c1f0a9e8d7c6b5a4938271605f4e3d2c1b0a9f8e7d6c5b4a392817","size":734003200,"uid":"6f1c2a8e-4b7d-4e2a-9c31-8d5e2f0a7b14"}

許可証:ペイロードと署名(それぞれbase64url)

eyJleHAiOjE3OTMzNDYwMDAsInB1cnBvc2UiOiJsYW50ZXJuLWdyYW50LTEiLCJzaGEyNTYiOiIzYTdiZDNlMmI0YzFmMGE5ZThkN2M2YjVhNDkzODI3MTYwNWY0ZTNkMmMxYjBhOWY4ZTdkNmM1YjRhMzkyODE3Iiwic2l6ZSI6NzM0MDAzMjAwLCJ1aWQiOiI2ZjFjMmE4ZS00YjdkLTRlMmEtOWMzMS04ZDVlMmYwYTdiMTQifQ.-4SQt-G8QN_sjMzKfaBGDl7b7Z-tW2qHaeC8bSwe70tHH4lVsyhxnMVMrb3r4y3RVBzbhOTeWdP4d6jFjex5Bg
public key (peers.key): FkDVKwFG57y5KAWiHAahZeQ1pO2FxI5AehF/nZjLXq8=

§ 19.3 · vectors/grants.json