Skip to content

Digital Agreement Signing

Self provides a secure digital agreement signing workflow that allows users to cryptographically sign documents using their digital identity. This workflow ensures document integrity, non-repudiation, and tamper-proof signatures that can be verified independently. The digital signing process is designed to be scalable and can be used in a variety of scenarios, such as:

  • Legal contract signing for business applications
  • Terms of service acceptance for web and mobile platforms
  • Document approval workflows in enterprise systems
  • Regulatory compliance documentation
  • Financial agreement signing
  • Healthcare consent forms

How to build a digital agreement signing workflow

You can build a secure digital agreement signing workflow with Self using verification requests and responses. Let's break down the process into steps:

1. Server: Verification Request

Once we have the user's address (userAddress) and the document to be signed, we can send a verification request. This request contains the document details and signing requirements. For more details on verification requests, check out the Verification guide.

2. Client: Handle Verification Request

You need to listen to the verification request in the account's callback and then check the incoming message for its type and details. If the request is for document signing, display the document content to the user for review and signature.

var verificationRequest: VerificationRequest? = null 
account.setOnRequestListener { msg ->
      when (msg) {
          is VerificationRequest -> {
              if (msg.types().contains("DocumentSigning") && msg.subject() == "document_signature") {                    
                  verificationRequest = msg

                  // Extract document content from the request
                  val documentContent = String(msg.attachment())
                  val documentHash = msg.obj()

                  // Navigate to document signing UI
                  navController.navigate("documentSigningRoute") 
              }
          }
      }
  }

  // Integrate document signing UI flow into Navigation
  addDocumentSigningRoute(navController, route = "documentSigningRoute", selfModifier = selfModifier, 
      document = { documentContent },
      onFinish = { accepted ->
          if (verificationRequest != null) {
              // Send the verification response after user decision
              sendVerificationResponse(accepted)               
          }            
      }
  )

  fun sendVerificationResponse(accepted: Boolean) {       
      val status = if (accepted) ResponseStatus.accepted else ResponseStatus.rejected

      val verificationResponse = VerificationResponse.Builder()
          .setRequestId(verificationRequest.id())
          .setTypes(verificationRequest.types())
          .setToIdentifier(verificationRequest.toIdentifier())
          .setFromIdentifier(verificationRequest.fromIdentifier())
          .setStatus(status)
          .setObject(verificationRequest.obj()) // Include document hash
          .setSubject(verificationRequest.subject())
          .build()

      account.send(verificationResponse)       
  }
// 1. Handle verification request in your request listener
func onMessage(message: any self_ios_sdk.Message) {
    print("onMessage: \(message)")
    switch message {
    case is VerificationRequest:
        let verificationRequest = message as! VerificationRequest
        Task { @MainActor in
            await self.handleVerificationRequest(verificationRequest)
        }
    default:
        print("🎯 ContentView: ❓ Unknown message type: \(type(of: message))")
        break
    }
}


// 2. Handle verification request with proper filtering and thread safety
private func handleVerificationRequest(_ verificationRequest: VerificationRequest) async {
    let types = verificationRequest.types()

    print("Verification request types: \(types)")

    // Check if this is a document signing request
    if types.contains("DocumentSigning") {
        print("✅ Processing document signing request")
        // show message view to process this verification request
    } else {
        print("❌ Unsupported verification request type")
    }
}

// 3. Show message view to process this verification request
self_ios_sdk.MessageView(account: account, message: verificationRequest) { result in
    switch result {
    case .success (let status):
        if status == MessageStatus.accepted.rawValue {
            print("Verification request accepted!")
        } else if status == MessageStatus.rejected.rawValue {
            print("Verification request rejected!")
        }
    case .failure(let error):
        print("Action failed: \(error)")
    }
}

See full examples

3. Server: Processing Signature Response, Document Integrity and Audit Trail

After receiving the verification response, we need to process the signature. This involves validating the response, checking the signature status, and storing the signed document record. For more information on verification validation, see the Verification Validation guide.

Security Considerations

When implementing digital agreement signing, consider these important security aspects:

Document Integrity

  • Always use cryptographic hashes (SHA-256 or stronger) to ensure document integrity
  • Store the original document hash with the signature record
  • Verify document hash before displaying to users

Non-Repudiation

  • Each signature is cryptographically linked to the signer's Self identity
  • Signature records include timestamps and metadata for audit trails
  • Digital signatures cannot be forged or denied by the signer
  • Self's digital signatures meet legal standards for electronic signatures in many jurisdictions
  • Maintain comprehensive audit logs for compliance requirements
  • Consider jurisdiction-specific requirements for digital signature validity

Best Practices

  • Implement signature expiration policies based on your use case
  • Store signature records in immutable audit logs
  • Provide clear consent mechanisms for users
  • Include document version control in your signing workflow

Conclusion

This example demonstrates how to build a comprehensive digital agreement signing workflow with Self. We've seen how to send verification requests for document signing, handle the signing process on mobile clients, validate signature responses, and maintain audit trails for compliance.

The Self SDK provides a secure, legally-compliant foundation for digital document signing that ensures: - Identity verification: Signers are authenticated using their Self digital identity - Document integrity: Cryptographic hashes prevent document tampering - Non-repudiation: Signatures cannot be denied or forged - Audit compliance: Comprehensive logging for regulatory requirements

💻 Complete Working Examples

For complete, runnable implementations that you can test immediately, explore our official examples repository:

🚀 Self SDK Examples Repository

Quick Start:

# Clone with all submodules
git clone --recurse-submodules https://github.com/joinself/self-sdk-examples.git

Platform-Specific Examples: - Android: android/SelfExamples/verification/ - Complete verification and document signing flow - iOS: ios/Example/ - Native iOS verification response implementation - Golang: golang/examples/ - Server-side verification request handling - Java: java/ - Enterprise server implementations

Key Features Demonstrated: - Document Hashing: Cryptographic document integrity verification - Signature Workflows: Complete request/response patterns for document signing - Audit Trails: Comprehensive logging and signature record management - Legal Compliance: Best practices for electronic signature validity

By leveraging these Self features, you can create a robust, secure, and legally-compliant digital signing system that streamlines agreement processes while maintaining the highest security standards.