DID-Based Authentication Protocol
Nip | Status | Type | Category | Created | Requires |
---|---|---|---|---|---|
2 | Draft | Standards Track | Core | 2024-05-12 | NIP-1 (DID Key Model) |
Abstract
This specification defines a general-purpose, decentralized authentication protocol based on NIP-1 DIDs. It enables any entity with a DID to prove its identity and the integrity of a message or request. The protocol leverages cryptographic signatures generated using keys associated with a DID, as registered in the corresponding DID document. It outlines a core authentication mechanism and then details its application across various communication patterns, including Agent-to-Agent (A2A) messaging, JSON-RPC services, and RESTful APIs, primarily utilizing the standard HTTP Authorization
header or embedded authentication structures for non-HTTP contexts.
Motivation
As decentralized systems and agent-based architectures evolve, a standardized, flexible, and secure authentication mechanism is crucial. NIP-1 provides a foundational DID key model. This NIP builds upon that by specifying how these DIDs and their associated keys can be used for robust authentication across diverse interaction protocols. The goal is to provide a unified approach to verifying the origin and integrity of communications, whether between autonomous agents, clients and servers, or other interacting components. This NIP addresses the need for a common authentication layer adaptable to HTTP-based interactions (like REST APIs and RPC over HTTP using the standard Authorization
header) as well as other message-oriented protocols.
Specification
Core DID Authentication Mechanism
This section describes the fundamental components and processes common to all applications of this DID-based authentication protocol.
1. Authentication Data Structure
At its core, the authentication information relies on the following data elements, typically serialized as a JSON object:
{
"signer_did": "did:example:...",
"key_id": "did:example:...#key-id",
"signature_value": "..."
}
Where:
signer_did
: DID of the entity performing the authentication.key_id
: Full key ID (verificationMethod id from DID doc) used for signing.signature_value
: Cryptographic signature (Base64 or Hex encoded).
2. Signed Content and Hashing
The signature_value
is a cryptographic signature calculated over a hash of the content being authenticated.
Hashing Process:
hash = HASH_ALGORITHM(domainSeparator + contentToSign)
HASH_ALGORITHM
: A strong cryptographic hash function (e.g., SHA256). The specific algorithm should be implied by the key type or explicitly defined by the application protocol.domainSeparator
: A protocol-specific string that clearly identifies the context of the signature (e.g.,"EXAMPLE_A2A_AUTH_V1:"
,"MY_RPC_API_V2_SIGNATURE:"
). This prevents replay attacks across different protocols or application domains. For services implementing the same protocol, each service provider should include its unique identifier in the domainSeparator (e.g.,"MY_API_V1_HTTP_AUTH:service-provider-id"
) to prevent cross-service replay attacks.contentToSign
: The actual data whose integrity and origin are being authenticated. This could be an HTTP request body, specific fields from a message, a JSON-RPC request object, or any other defined payload. This content must include atimestamp
(e.g., Unix timestamp in seconds) and anonce
(a unique random string) to prevent replay attacks.
3. General Authentication Flow (Conceptual)
The flow involves a Signer (the entity authenticating) and a Verifier (the entity validating the authentication).
Steps:
- Message/Request Construction (Signer): The Signer constructs the primary message or request. This payload must include a
timestamp
and anonce
. - Identify Identity and Key (Signer): The Signer identifies its
signer_did
and the specifickey_id
to be used for signing. This key must be listed in theverificationMethod
section of thesigner_did
’s DID document. - Define Content and Separator (Signer): The Signer determines the exact
contentToSign
and the appropriatedomainSeparator
. - Hash Generation (Signer): The Signer calculates the hash.
- Signing (Signer): The Signer signs the hash using the private key corresponding to
key_id
. - Assemble Authentication Data (Signer): The Signer creates the JSON structure with
signer_did
,key_id
, andsignature_value
. - Transmit (Signer): The Signer sends the original message/request along with the assembled authentication data (e.g., in an HTTP header or embedded in the message).
- Receive and Parse (Verifier): The Verifier receives the message/request and the authentication data. It parses the authentication data.
- Verify Replay Protection (Verifier): The Verifier extracts
timestamp
andnonce
from the received message/request. It checks if thetimestamp
is within an acceptable window and if thenonce
has not been used before by thissigner_did
. - Recalculate Hash (Verifier): The Verifier reconstructs the
contentToSign
from the received message/request and uses the samedomainSeparator
andHASH_ALGORITHM
to calculatehashToVerify
. - Resolve DID and Get Public Key (Verifier): The Verifier resolves
signer_did
to get its DID document, then finds the public key information associated withkey_id
. - Verify Signature (Verifier): The Verifier uses the public key to validate the
signature_value
againsthashToVerify
. - Verify Permissions (Verifier): The Verifier checks if the
key_id
is authorized for authentication, typically by checking its presence in theauthentication
verification relationship in the DID document. - Confirmation (Verifier): If all checks pass, the Verifier confirms the Signer’s identity as
signer_did
.
Application: HTTP-based Authentication (REST APIs, RPC over HTTP)
For services communicating over HTTP (e.g., RESTful APIs, JSON-RPC over HTTP), authentication is conveyed via the standard Authorization
HTTP header.
1. HTTP Header
The Authorization
HTTP header is used with the DIDAuthV1
scheme. The header is constructed as follows:
Authorization: DIDAuthV1 <credentials>
Where <credentials>
must be the Base64url encoding of the UTF-8 encoded JSON string representing the Core Authentication Data Structure.
2. Signed Content (contentToSign
)
For HTTP-based authentication, contentToSign
typically includes:
- The full HTTP request body.
- Optionally, other parts of the HTTP request (e.g., method, path, relevant headers) can be canonicalized and included if they need to be part of the integrity check. The exact definition of
contentToSign
must be specified by the API or service. - Crucially, the
timestamp
andnonce
values used in the hashing process must be present in the request body or headers, as defined by the service, to allow the verifier to perform replay protection.
Example domainSeparator
for an HTTP API: "MY_API_V1_HTTP_AUTH:"
3. Error Handling
Failures should result in standard HTTP error responses (e.g., 401 Unauthorized
, 400 Bad Request
), potentially with a JSON body detailing the specific error based on NIP-2 codes (see “General Error Codes” below).
Application: Agent-to-Agent (A2A) Communication
For Agent-to-Agent (A2A) communication:
- If the A2A communication occurs over HTTP, the HTTP-based authentication method described above (using the
Authorization: DIDAuthV1 <credentials>
header) should be used. - If A2A communication uses a non-HTTP transport, or if direct embedding of authentication data within the message payload is preferred for specific protocol reasons, the following embedded mechanism can be used.
1. Protocol Identifier (for embedded method)
The scheme is identified by did-auth-v1
.
2. Embedded Authentication Structure (for non-HTTP or preferred embedding)
An A2A message requiring authentication (when not using the HTTP Authorization
header method) would include a field (e.g., authentication
) structured as:
{
"schemes": ["did-auth-v1"],
"credentials": "<json_string_of_core_auth_data>"
}
Where credentials
is the JSON string of the Core Authentication Data Structure.
3. Signed Content (contentToSign
) (for embedded method)
For A2A using the embedded method, contentToSign
is typically the message.parts
object (or a similar well-defined part of the A2A message payload), which must include timestamp
and nonce
.
Example domainSeparator
for A2A (embedded method): "EXAMPLE_A2A_EMBEDDED_AUTH_V1:"
4. Error Handling (for embedded method)
Errors are typically handled according to the A2A protocol’s error reporting mechanisms, using NIP-2 error codes (see “General Error Codes” below).
General Error Codes
These error codes can be adapted for use in HTTP responses or embedded error structures.
- DID Resolution Failed: Could not resolve
signer_did
or fetch the DID document. (e.g., JSON-RPC:-32004
) - Key Not Found:
key_id
not found in the DID document. (e.g., JSON-RPC: part of-32001
) - Permission Denied:
key_id
not present in the required verification relationship (e.g.,authentication
). (e.g., JSON-RPC: part of-32001
) - Invalid Signature: Signature verification failed. (e.g., JSON-RPC: part of
-32001
) - Replay Attack Detected:
nonce
reused or invalidtimestamp
. (e.g., JSON-RPC:-32005
) - Invalid Authentication Format: Authentication data (e.g.,
Authorization
header withDIDAuthV1
scheme, orcredentials
field in embedded A2A) is missing, malformed, or fails decoding/parsing. (e.g., HTTP:400 Bad Request
; JSON-RPC:-32602 Invalid Params
) - Authentication Required: Authentication information was not provided. (e.g., HTTP:
401 Unauthorized
; JSON-RPC:-32002
) - Unsupported Scheme: The authentication scheme is not supported (relevant if multiple schemes can be indicated, or if
DIDAuthV1
is not supported by the verifier). (e.g., JSON-RPC:-32003
)
Rationale
(Placeholder: Detailed rationale to be added. Key design choices include: a general core mechanism for broad applicability, use of domain separators for security, inclusion of timestamp/nonce for replay protection, specific adaptations for HTTP and A2A common patterns.)
Using the standard Authorization
HTTP header with a custom scheme (DIDAuthV1
) for REST/RPC APIs aligns with common HTTP practices (e.g., Bearer
, Basic
schemes) and avoids proliferation of custom headers. This makes it easier for existing HTTP infrastructure and libraries to handle.
For A2A communication, prioritizing the HTTP Authorization
header method when A2A occurs over HTTP promotes consistency. The embedded authentication data structure is provided for scenarios where A2A does not run over HTTP or where direct message-level security is preferred.
The JSON structure for authentication data is chosen for its widespread support and ease of parsing. Base64url encoding for the credentials in the Authorization
header is standard for such use cases.
Backwards Compatibility
(Placeholder: Details on backwards compatibility to be added. This NIP defines new authentication mechanisms. Systems not implementing it will not understand the Authorization
header with the DIDAuthV1
scheme or the did-auth-v1
scheme in embedded A2A messages. Services can choose to support multiple authentication schemes for transition periods.)
Test Cases
(Placeholder: Test cases to be added, covering: valid/invalid signatures for HTTP and A2A, replay attempts, DID resolution failures, key permission issues, malformed headers/credentials.)
Reference Implementation
(Placeholder: Link to reference implementation to be added.)
Security Considerations
- Inherited from NIP-1: Security relies heavily on NIP-1’s DID method security, key management, and DID document integrity.
- Replay Attacks: Strict validation of
timestamp
andnonce
is critical. Verifiers must maintain stateful nonce storage scoped bysigner_did
anddomainSeparator
. The nonce storage should be cleaned up periodically to prevent unbounded growth. - Service Provider Identification: Each service provider implementing the same protocol should use a unique identifier in its
domainSeparator
to prevent cross-service replay attacks. This is especially important when multiple services implement the same protocol. - Nonce Management:
- Nonces should be generated using cryptographically secure random number generators
- Nonce storage should be implemented using distributed caching solutions for distributed service architectures
- Nonce validation should be scoped by both
signer_did
anddomainSeparator
- Nonce storage should be cleaned up after the timestamp validation window expires
- Transport Security: Communication channels (e.g., HTTP, A2A transport) must use TLS/HTTPS or equivalent transport-layer security to protect confidentiality and integrity of the entire exchange, including authentication data.
- DID Resolver Security: Verifiers must use a trusted DID resolver.
- Verification Relationship Check: Verifiers must check that the signing key (
key_id
) is present in the appropriate verification relationship (usuallyauthentication
) in the DID document. - Domain Separator: The
domainSeparator
is crucial to prevent cross-protocol or cross-application signature replay. It must be unique and well-defined for each application of this NIP. - Signature Scope (
contentToSign
): The definition ofcontentToSign
must be precise and cover all security-relevant parts of the message/request. Ambiguity can lead to vulnerabilities. - Header/Credential Integrity: For HTTP, ensure infrastructure (proxies, gateways) doesn’t unintentionally modify or strip the
Authorization
header. For embedded credentials, ensure they are part of the overall message integrity protection if available. - Key Compromise: Revocation mechanisms for compromised keys (as defined by the DID method and NIP-1) are essential. Verifiers should fetch fresh DID documents or use a resolver that respects DID document caching and update rules.
Copyright
Copyright and related rights waived via CC0 .