Abstract

This specification defines a method for authenticating HTTP requests using Schnorr signatures, providing a decentralized and secure authentication mechanism. By leveraging Schnorr signatures, widely used in Bitcoin Taproot and the Nostr protocol, this method enables seamless integration with decentralized networks and services.

Status of This Document

This is a draft document of the W3C Nostr Community Group and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

This document was produced by a group operating under the W3C Community Contributor License Agreement (CLA).

Conformance

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [[RFC2119]] [[RFC8174]] when, and only when, they appear in all capitals, as shown here.

Introduction

Motivation

The rise of decentralized applications and services necessitates secure and user-centric authentication mechanisms. Traditional centralized authentication methods often introduce single points of failure and privacy concerns. By utilizing Schnorr signatures for HTTP authentication, we can achieve a decentralized, secure, and privacy-preserving authentication protocol suitable for modern web applications.

Background on Schnorr Signatures

Schnorr signatures are digital signature schemes known for their simplicity, efficiency, and provable security. They are extensively used in blockchain technologies such as Bitcoin and Litecoin. Their non-malleability and linearity properties make them ideal for complex cryptographic protocols.

Relation to Existing Standards

This specification builds upon the concepts introduced in RFC 7235 (HTTP/1.1 Authentication) and extends the authentication framework to support Schnorr signatures. It also aligns with efforts in decentralized networks like Nostr and projects like Solid that explore signature-based authentication.

Use Cases

Single Sign-On (SSO)

Enable users to authenticate across multiple services using a single cryptographic identity, eliminating the need for passwords and reducing friction in the user experience.

Decentralized Authentication

Facilitate authentication in decentralized applications where traditional centralized authentication methods are not viable, enhancing security and user control over personal data.

Integration with Blockchain Networks

Leverage existing cryptographic keys from blockchain networks like Bitcoin, allowing users to authenticate with services using the same keys that control their digital assets.

Terminology

Client
An entity that initiates an HTTP request requiring authentication.
Server
An entity that responds to the HTTP request and validates the authentication information.
Schnorr Signature
A cryptographic digital signature produced using the Schnorr signature scheme.
Event
A JSON object containing authentication data, signed by the client's private key.

Protocol Overview

The authentication protocol utilizes a signed JSON event included in the HTTP Authorization header. The event contains necessary information for the server to validate the request, including the request URL, HTTP method, and a timestamp.

Protocol Diagram

Protocol Sequence Diagram

Event Structure

The event is a JSON object with the following fields. The complete JSON structure is defined in the ABNF grammar section, and individual field formats are specified in the Event Field Formats.

Event Serialization

Events MUST be serialized according to the canonical JSON format specified in [[NIP01]]. The serialization process is as follows:

  1. Create a JSON array containing exactly these elements in order:
    • 0 (integer, always zero)
    • pubkey (string, lowercase hexadecimal)
    • created_at (integer, UNIX timestamp)
    • kind (integer, must be 27235)
    • tags (array of arrays, sorted lexicographically)
    • content (string, should be empty)
  2. Serialize the array to JSON with no extra whitespace
  3. Encode the resulting string as UTF-8 bytes

Event ID Calculation

The id field MUST be calculated as follows:

  1. Serialize the event as specified in the Event Serialization section
  2. Compute the SHA-256 hash of the serialized UTF-8 bytes
  3. Encode the hash as a lowercase hexadecimal string

Signature Creation

The sig field MUST be created as follows:

  1. Calculate the event ID as specified in the Event ID Calculation section
  2. Convert the hexadecimal event ID to 32 bytes
  3. Sign the 32-byte hash using the secp256k1 Schnorr signature algorithm as specified in [[BIP340]]
  4. Encode the 64-byte signature as a lowercase hexadecimal string

Authentication Flow

  1. The client constructs the event with the required fields and signs it using their private key.
  2. The client includes the base64-encoded event in the Authorization header with the scheme Nostr.
  3. The server receives the request and validates the event as per the Event Validation section.
  4. Upon successful validation, the server processes the request; otherwise, it responds with 401 Unauthorized.

ABNF Grammar

This section provides formal syntax definitions using Augmented Backus-Naur Form (ABNF) as specified in [[RFC5234]]. These grammar rules define the precise format requirements for all protocol elements.

Authorization Header


nostr-auth     = "Authorization:" OWS "Nostr" 1*SP b64token OWS
b64token       = 1*( ALPHA / DIGIT / "+" / "/" ) *2"="
      

Event Field Formats


event-id       = 64HEXDIG
public-key     = 64HEXDIG
signature      = 128HEXDIG
unix-timestamp = 1*DIGIT
kind-value     = "27235"
content-field  = ""
      

Tag Formats


url-tag        = "[" DQUOTE "u" DQUOTE "," OWS DQUOTE absolute-URI DQUOTE "]"
method-tag     = "[" DQUOTE "method" DQUOTE "," OWS DQUOTE http-method DQUOTE "]"
payload-tag    = "[" DQUOTE "payload" DQUOTE "," OWS DQUOTE 64HEXDIG DQUOTE "]"
webid-tag      = "[" DQUOTE "webid" DQUOTE "," OWS DQUOTE absolute-URI DQUOTE "]"
      

Base Definitions


http-method    = "GET" / "POST" / "PUT" / "DELETE" / "PATCH" / "HEAD" / "OPTIONS"
absolute-URI   = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
scheme         = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
hier-part      = "//" authority path-absolute / path-absolute / path-rootless / path-empty
authority      = [ userinfo "@" ] host [ ":" port ]
path-absolute  = "/" [ segment-nz *( "/" segment ) ]
query          = *( pchar / "/" / "?" )
fragment       = *( pchar / "/" / "?" )
HEXDIG         = DIGIT / "A" / "B" / "C" / "D" / "E" / "F" / "a" / "b" / "c" / "d" / "e" / "f"
64HEXDIG       = 64HEXDIG-rule
64HEXDIG-rule  = HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG
                 HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG
                 HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG
                 HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG
                 HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG
                 HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG
                 HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG
                 HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG
128HEXDIG      = 128HEXDIG-rule
128HEXDIG-rule = 64HEXDIG-rule 64HEXDIG-rule

; Core ABNF rules from RFC 5234
ALPHA          = %x41-5A / %x61-7A   ; A-Z / a-z
DIGIT          = %x30-39             ; 0-9
DQUOTE         = %x22                ; " (Double Quote)
SP             = %x20                ; space
OWS            = *( SP / HTAB )      ; optional whitespace
HTAB           = %x09                ; horizontal tab
      

JSON Event Structure


event-object   = "{" 
                   DQUOTE "id" DQUOTE ":" DQUOTE event-id DQUOTE ","
                   DQUOTE "pubkey" DQUOTE ":" DQUOTE public-key DQUOTE ","
                   DQUOTE "created_at" DQUOTE ":" unix-timestamp ","
                   DQUOTE "kind" DQUOTE ":" kind-value ","
                   DQUOTE "tags" DQUOTE ":" tags-array ","
                   DQUOTE "content" DQUOTE ":" DQUOTE content-field DQUOTE ","
                   DQUOTE "sig" DQUOTE ":" DQUOTE signature DQUOTE
                 "}"

tags-array     = "[" [ tag-element *( "," tag-element ) ] "]"
tag-element    = url-tag / method-tag / payload-tag / webid-tag
      

HTTP Authorization Header

The client MUST include the signed event in the Authorization header using the Nostr scheme. The event MUST be base64-encoded.

Header Format

The Authorization header MUST conform to the ABNF grammar definition.

Authorization: Nostr <base64-encoded-event>

Example

Authorization: Nostr eyJpZCI6ImZlOTY0ZTc1ODkwMzM2MGYyOGQ4MjQ0ZDA5MmRhODQ5NGVkMjA3Y2JhODIzMTEwYmUzYTU3ZGZlNGI1Nzg3MzQiLCJwdWJrZXkiOiI2M2ZlNjMxOGRjNTg1ODNjZmUxNjgxMGY4NmRkMDllMThiZmQ3NmFhYmMyNGEwMDgxY2UyODU2ZjMzMDUwNGVkIiwiY29udGVudCI6IiIsImtpbmQiOjI3MjM1LCJjcmVhdGVkX2F0IjoxNjgyMzI3ODUyLCJ0YWdzIjpbWyJ1IiwiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20vcmVzb3VyY2UiXSxbIm1ldGhvZCIsIkdFVCJdXSwiY2FsbGJhY2siOm51bGwsInNpZyI6IjVlZDlkOGVjOTU4YmM4NTRmOTk3YmRjMjRhYzMzN2QwMDVhZjM3MjMyNDc0N2VmZTRhMDBlMjRmNGMzMDQzN2ZmNGRkODMwODY4NGJlZDQ2N2Q5ZDZiZTNlNWE1MTdiYjQzYjE3MzJjYzdkMzk0OWEzYWFmODY3MDVjMjIxODQifQ==

Event Validation

Servers MUST perform the following checks to validate the event:

  1. Kind Check: The kind field MUST be 27235.
  2. Timestamp Check: The created_at timestamp MUST be within a reasonable time window (e.g., ±60 seconds of the server's current time).
  3. URL Match: The ["u", "<absolute-URL>"] tag MUST exactly match the absolute request URL, including query parameters.
  4. Method Match: The ["method", "<HTTP-method>"] tag MUST match the HTTP method used for the request.
  5. Signature Verification: The sig field MUST be a valid secp256k1 Schnorr signature as specified in [[BIP340]], verifiable using the pubkey and the event ID calculated according to the Event ID Calculation section.
  6. Payload Hash Check (optional): If the request includes a body and the event contains a ["payload", "<sha256-hex>"] tag, the SHA-256 hash of the request body MUST match the provided hash.
  7. WebID Validation (optional): If the event includes a ["webid", "<identity-uri>"] tag, the server MAY perform identity-based validation as specified in the Identity Integration section.

If any of these checks fail, the server SHOULD respond with 401 Unauthorized.

Additional Validation

Servers MAY perform additional implementation-specific validation checks, such as rate limiting or public key blacklisting.

Identity Integration

This specification supports integration with decentralized identity systems to enable automatic public key discovery and identity verification through WebID profiles and DID:nostr identifiers.

WebID Profile Integration

WebID profiles MUST link to secp256k1 public keys to enable automatic key discovery. The profile SHOULD include the public key using the following RDF vocabulary:


@prefix cert: <http://www.w3.org/ns/auth/cert#> .
@prefix nostr: <https://w3id.org/nostr/vocab#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .

<https://alice.example/profile#me> a foaf:Person ;
    nostr:pubkey "63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed" ;
    cert:key [
        a cert:PublicKey ;
        nostr:pubkey "63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed" ;
        cert:exponent 65537 ;
        cert:modulus "abc123..."^^xsd:hexBinary
    ] .
      

DID:nostr Integration

This specification aligns with the DID:nostr method as specified in [[DID-NOSTR]]. DID:nostr identifiers encode the public key directly and provide a standardized resolution mechanism:


did:nostr:npub1v0lxx8xtp4vzlet3sgm3xmgne8x0majkys9qpq7v2pt0xvcq2nx4svlx5kj
      

The public key can be extracted from the DID identifier using the bech32 decoding process specified in the DID:nostr method.

Identity Discovery Flow

When a webid tag is present in the authentication event, servers MAY perform identity-based validation:

  1. Extract the identity URI from the ["webid", "<identity-uri>"] tag
  2. Resolve the identity document:
    • For https:// URIs: Fetch WebID profile and parse RDF
    • For did:nostr: URIs: Extract public key from DID identifier
  3. Extract the linked secp256k1 public key from the identity document
  4. Verify that the discovered public key matches the pubkey field in the event
  5. Perform standard signature verification using the discovered key
  6. Apply any additional identity-specific authorization policies

Enhanced WebID Validation

When performing WebID-based validation, servers SHOULD implement the following requirements:

Security Considerations

Privacy Considerations

References

Normative References

[RFC7235]
Fielding, R., and Reschke, J., "Hypertext Transfer Protocol (HTTP/1.1): Authentication", RFC 7235, June 2014. https://www.rfc-editor.org/rfc/rfc7235
[RFC6234]
Eastlake 3rd, D. and T. Hansen, "US Secure Hash Algorithms (SHA and SHA-based HMAC and HKDF)", RFC 6234, May 2011. https://www.rfc-editor.org/rfc/rfc6234

Informative References

[Schnorr]
Wikipedia, "Schnorr Signature", https://en.wikipedia.org/wiki/Schnorr_signature
[Nostr]
Nostr Protocol, https://github.com/nostr-protocol
[Solid]
Solid Project, https://solidproject.org/

Acknowledgments

Special thanks to the members of the W3C Nostr Community Group and the broader community for their valuable feedback and contributions.