Security
Secure interactions with DID Spaces are paramount. The DID Spaces SDK employs robust request signing and delegation mechanisms to ensure the authenticity and integrity of all communications. This section delves into how these security features are implemented and utilized, protecting your data and operations.
For an understanding of how these mechanisms integrate with the client, refer to the Client documentation.
Request Signing#
The signRequest
method is used to sign outgoing requests, ensuring that the request originates from a trusted source and has not been tampered with in transit. It generates a JSON Web Token (JWT) containing a digest of the request's critical components (URL, method, and data), signed by the application's wallet.
Parameters
Name | Type | Description |
---|---|---|
|
| The URL of the request. |
|
| The HTTP method of the request (e.g., |
|
| The request body or payload. |
|
| Existing request headers. |
|
| The |
|
| Optional. A delegation JWT if the request is being made on behalf of another DID. |
Returns
Name | Type | Description |
---|---|---|
|
| The original request URL. |
|
| The original request method. |
|
| The original request data. |
|
| The updated headers including |
Example
import { signRequest } from '@arcblock/did-spaces-client/security';
import { Wallet } from '@ocap/wallet';
async function createSignedRequest(wallet, spaceUrl) {
const requestPayload = {
url: `${spaceUrl}/api/v2/objects/my-file.txt`,
method: 'PUT',
data: { data: 'Hello DID Spaces!' },
headers: { 'Content-Type': 'application/json' },
};
try {
const signedRequest = await signRequest({
...requestPayload,
wallet,
// delegation: 'your-delegation-token' // Optional delegation token
});
console.log('Signed Request Headers:', signedRequest.headers);
// Send the signedRequest to the DID Space server
} catch (error) {
console.error('Error signing request:', error.message);
}
}
// Assuming you have a wallet instance
const myWallet = Wallet.fromRandom(); // In a real app, load from secure storage
createSignedRequest(myWallet, 'https://my.did.space');
This example demonstrates how to use signRequest
to add the necessary authentication headers to an outgoing HTTP request. The x-app-did
, x-app-pk
, and x-app-token
headers are automatically populated, with x-app-token
containing the signed JWT.
Request Verification#
The verifyRequest
method is used on the server-side to validate incoming requests. It checks the integrity of the request by verifying the JWT signature and the digest of the request's content against the provided headers.
Parameters
Name | Type | Description |
---|---|---|
|
| The URL of the incoming request. |
|
| The HTTP method of the incoming request. |
|
| The request body or payload. |
|
| The request headers, expected to contain |
Returns
Name | Type | Description |
---|---|---|
|
| The Decentralized Identifier (DID) of the authenticated application (or delegator if a delegation token is present). |
Example
import { verifyRequest } from '@arcblock/did-spaces-client/security';
async function verifyIncomingRequest(req) {
// In a real application, req would be an Express.js request object or similar
const { url, method, body, headers } = req;
try {
const appDid = await verifyRequest({
url,
method,
data: body,
headers: {
'x-app-did': headers['x-app-did'],
'x-app-pk': headers['x-app-pk'],
'x-app-token': headers['x-app-token'],
'x-app-delegation': headers['x-app-delegation'] || '',
},
});
console.log(`Request successfully verified from DID: ${appDid}`);
// Proceed with processing the request
} catch (error) {
console.error('Request verification failed:', error.message);
// Reject the request
}
}
// Example usage (conceptual for a server-side handler)
// verifyIncomingRequest({ /* mock request object */ });
This example illustrates how verifyRequest
can be used to validate the authenticity and integrity of a request received by a DID Space server. It returns the authenticated application's DID if valid, otherwise throws an error.
Delegation Verification#
The verifyDelegation
function is a utility to validate a delegation JWT, ensuring it's properly signed and that the delegated permissions are valid for the intended delegatee. This is internally used by signRequest
and verifyRequest
when a delegation token is provided.
Parameters
Name | Type | Description |
---|---|---|
|
| The delegation JWT string. |
|
| The |
Returns
Name | Type | Description |
---|---|---|
|
| The DID of the delegator (the original issuer of the delegation) if the delegation is valid. |
Example
import { verifyDelegation } from '@arcblock/did-spaces-client/security';
import { fromPublicKey } from '@ocap/wallet';
import { toTypeInfo } from '@arcblock/did';
async function checkDelegation(delegationToken, appPublicKey, appDid) {
try {
const delegateeWallet = fromPublicKey(appPublicKey, toTypeInfo(appDid));
const delegatorDid = await verifyDelegation(delegationToken, delegateeWallet);
console.log(`Delegation valid. Original delegator DID: ${delegatorDid}`);
} catch (error) {
console.error('Delegation verification failed:', error.message);
}
}
// Example usage (replace with actual values)
// const exampleDelegationToken = 'eyJhbGci...';
// const exampleAppPublicKey = 'z2123...';
// const exampleAppDid = 'did:abt:z2123...';
// checkDelegation(exampleDelegationToken, exampleAppPublicKey, exampleAppDid);
This example shows how to manually verify a delegation token. It's crucial for understanding how the SDK determines the true identity behind a delegated request.
DID Document Security#
DID Documents are central to DID-based identity. The SDK provides utilities to sign and verify these documents, ensuring their integrity and authenticity.
DID Document Structure#
The DidDocument
interface defines the standard structure for a Decentralized Identifier Document, as per W3C DID Core specifications. It includes essential identity information, verification methods, service endpoints, and proof mechanisms.
interface DidDocument {
'@context': 'https://www.w3.org/ns/did/v1';
id: string; // The DID subject (e.g., did:abt:xxx)
controller: string; // The DID that controls this document (often the same as id)
service: Array<{ // Service endpoints associated with the DID
id: string;
type: string;
key?: string; // v0.2 onwards
serviceEndpoint: string;
[key: string]: string | undefined;
}>;
verificationMethod: Array<{ // Public keys and other verification material
id: string;
type: string;
controller: string;
publicKeyMultibase: string;
}>;
proof: { // Digital signature proof of the document's integrity
type: string;
created: string;
verificationMethod: string;
jws?: string; // The JWS signature
};
authentication: string[]; // Reference to verification methods for authentication
created: string; // Timestamp of creation
updated: string; // Timestamp of last update
}
Sign DID Document (signDidDocument
)#
This method signs a DidDocument
using a provided WalletObject
, embedding the signature into the proof.jws
field. This ensures that the document's content can be cryptographically verified.
Parameters
Name | Type | Description |
---|---|---|
|
| The DID Document to be signed. |
|
| The |
Returns
Name | Type | Description |
---|---|---|
|
| The signed DID Document, with the |
Example
import { signDidDocument } from '@arcblock/did-spaces-client/did-document';
import { Wallet } from '@ocap/wallet';
async function signMyDidDocument(myDidDocument, controllerWallet) {
try {
const signedDocument = signDidDocument(myDidDocument, controllerWallet);
console.log('Signed DID Document:', signedDocument.proof.jws);
return signedDocument;
} catch (error) {
console.error('Error signing DID Document:', error.message);
}
}
// Example DID Document (conceptual)
// const myDoc = {
// '@context': 'https://www.w3.org/ns/did/v1',
// id: 'did:abt:zNYSsYxQJ3e...', // Your DID
// controller: 'did:abt:zNYSsYxQJ3e...', // Your DID
// // ... other fields
// proof: {
// type: 'Secp256k1Signature2019',
// created: new Date().toISOString(),
// verificationMethod: 'did:abt:zNYSsYxQJ3e...#controller',
// },
// authentication: ['did:abt:zNYSsYxQJ3e...#controller'],
// created: new Date().toISOString(),
// updated: new Date().toISOString(),
// };
// const controllerWallet = Wallet.fromRandom(); // Replace with your actual wallet
// signMyDidDocument(myDoc, controllerWallet);
This example shows how to sign a DidDocument
using a wallet, adding the JSON Web Signature (JWS) to its proof
section.
Verify DID Document (verifyDidDocument
)#
This method verifies the digital signature of a DidDocument
. It ensures that the document has not been altered and was signed by the legitimate controller, as indicated by its proof
section.
Parameters
Name | Type | Description |
---|---|---|
|
| The DID Document to be verified. |
Returns
Name | Type | Description |
---|---|---|
|
| Resolves if the document's signature is valid; otherwise, it throws an |
Example
import { verifyDidDocument } from '@arcblock/did-spaces-client/did-document';
async function verifyReceivedDidDocument(receivedDidDocument) {
try {
await verifyDidDocument(receivedDidDocument);
console.log('DID Document is valid and verified.');
} catch (error) {
console.error('DID Document verification failed:', error.message);
}
}
// Example usage with a previously signed DID Document
// const receivedDoc = { /* ... a DidDocument with a proof.jws field ... */ };
// verifyReceivedDidDocument(receivedDoc);
This example demonstrates how to verify the integrity and authenticity of a received DidDocument
using its embedded signature.
Security Flow Overview#
The following diagram illustrates the general flow of request signing and verification within the DID Spaces SDK:
Understanding these security mechanisms is crucial for building reliable and secure applications on DID Spaces. You are now equipped with the knowledge of how requests are signed, verified, and how DID Documents are secured within the SDK. Proceed to the Commands Reference to explore the full range of operations available.