On-Chain Authorization

Stake-based service registration system using DNS verification and UCAN capabilities for decentralized authentication and authorization

On-Chain Authorization

Scope

This document covers Sonr's service registration and authorization system, including stake-based trust models, DNS verification, UCAN capability delegation, and reputation tracking. It explains technical architecture, integration patterns, and economic incentives. This document does not cover implementation details or pricing comparisons—see the Service Module reference for technical specifications.

Audience

Service developers building authenticated applications. System architects designing authorization systems. Validators participating in service verification. Prerequisites: Understanding of DNS verification, capability-based security, and stake-based economics.

Summary

Sonr implements on-chain service authorization through stake-based registration, DNS verification, and UCAN capabilities. Services stake SNR tokens to register, prove domain ownership via DNS TXT records, and request user permissions through capability tokens. The system builds trust through successful authentication metrics, creating decentralized reputation without central authorities.

Architecture Overview

Core Components

The service authorization system consists of four components:

  1. Service Registry: On-chain registry of verified services
  2. DNS Verification: Domain ownership proof via TXT records
  3. Stake Management: Economic incentives through token staking
  4. Reputation Tracking: Performance metrics and trust scores

System Flow

Technical Implementation

Service Registration

Services register through staking and domain verification:

// Service registration structure
interface ServiceRegistration {
  domain: string; // Verified domain
  stakeAmount: number; // SNR tokens staked
  capabilities: string[]; // Requested permissions
  operator: string; // Service operator DID
}

// Registration process
async function registerService(params: ServiceRegistration) {
  // 1. Verify minimum stake
  if (params.stakeAmount < MIN_STAKE) {
    throw new Error("Insufficient stake");
  }

  // 2. Verify domain ownership
  const verified = await verifyDomain(params.domain);
  if (!verified) {
    throw new Error("Domain verification failed");
  }

  // 3. Lock stake
  await lockStake(params.operator, params.stakeAmount);

  // 4. Register on-chain
  return await registry.register(params);
}

Trust Score Calculation

Reputation emerges from authentication metrics:

interface TrustMetrics {
  totalAuthentications: number;
  successRate: number; // Percentage (0-100)
  avgResponseTime: number; // Milliseconds
  userSatisfaction: number; // Score (0-10)
  timeActive: number; // Days since registration
  slashingEvents: number; // Count of penalties
}

function calculateTrustScore(metrics: TrustMetrics, stake: number): number {
  // Weight components
  const stakeWeight = Math.min(stake / 10000, 1) * 0.25;
  const successWeight = (metrics.successRate / 100) * 0.3;
  const volumeWeight = Math.min(metrics.totalAuthentications / 100000, 1) * 0.2;
  const timeWeight = Math.min(metrics.timeActive / 365, 1) * 0.15;
  const satisfactionWeight = (metrics.userSatisfaction / 10) * 0.1;

  // Apply penalties
  const slashingPenalty = metrics.slashingEvents * 0.1;

  // Calculate final score (0-1000)
  return Math.max(
    0,
    (stakeWeight +
      successWeight +
      volumeWeight +
      timeWeight +
      satisfactionWeight) *
      1000 -
      slashingPenalty,
  );
}

Slashing Conditions

Staked tokens are slashed for violations:

type SlashingCondition struct {
    Type     string
    Severity string  // minor, major, severe
    Penalty  sdk.Dec // Percentage of stake
}

var slashingConditions = []SlashingCondition{
    // Minor violations (1-5%)
    {"slow_response", "minor", sdk.NewDec(1)},
    {"user_complaint", "minor", sdk.NewDec(2)},
    {"downtime", "minor", sdk.NewDec(3)},

    // Major violations (10-30%)
    {"data_breach", "major", sdk.NewDec(25)},
    {"privacy_violation", "major", sdk.NewDec(30)},

    // Severe violations (50-100%)
    {"malicious_behavior", "severe", sdk.NewDec(75)},
    {"fraud", "severe", sdk.NewDec(100)},
}

DNS Verification

Registration Process

Services prove domain ownership through DNS TXT records:

# 1. Initiate verification
sonrd tx svc initiate-domain-verification example.com --from alice

# 2. Add TXT record to DNS provider
TXT: sonr-verification=a1b2c3d4e5f6789...

# 3. Verify ownership
sonrd tx svc verify-domain example.com --from alice

# 4. Register service
sonrd tx svc register-service my-app example.com \
  --capabilities="dwn:read,dwn:write,payment:request" \
  --stake-amount=5000 \
  --from alice

Verification Implementation

DNS verification uses standard TXT record lookup:

func (k Keeper) VerifyDomainOwnership(
    ctx context.Context,
    domain string,
) error {
    // Get verification token
    verification, err := k.DomainVerifications.Get(ctx, domain)
    if err != nil {
        return err
    }

    // Lookup DNS TXT records
    expectedRecord := fmt.Sprintf(
        "sonr-verification=%s",
        verification.VerificationToken,
    )

    txtRecords, err := net.LookupTXT(domain)
    if err != nil {
        return fmt.Errorf("DNS lookup failed: %w", err)
    }

    // Check for verification record
    for _, record := range txtRecords {
        if strings.TrimSpace(record) == expectedRecord {
            verification.Status = VERIFIED
            return k.DomainVerifications.Save(ctx, verification)
        }
    }

    return fmt.Errorf("verification record not found")
}

DNS Provider Compatibility

Works with any DNS provider:

# Example DNS configuration
example.com.    TXT    "sonr-verification=a1b2c3d4e5f6789abcdef"
example.com.    A      192.168.1.1
www.example.com CNAME  example.com

Supported providers include:

  • Cloudflare
  • AWS Route53
  • Google Cloud DNS
  • GoDaddy
  • Namecheap
  • Any RFC-compliant DNS service

UCAN Authorization

Capability Requests

Services request permissions through UCAN tokens:

interface CapabilityRequest {
  service: string; // Verified domain
  user: string; // User DID
  capabilities: {
    resource: string; // Target resource
    actions: string[]; // Requested actions
    constraints?: {
      amount?: string; // Spending limits
      frequency?: string; // Time restrictions
      expires?: number; // Expiration timestamp
    };
  }[];
}

// Request data access
const dataRequest: CapabilityRequest = {
  service: "app.example.com",
  user: "did:sonr:alice123",
  capabilities: [
    {
      resource: "sonr://vault/alice123/data",
      actions: ["dwn:read", "dwn:write"],
      constraints: {
        dataTypes: ["profile", "settings"],
        expires: Date.now() + 30 * 24 * 60 * 60 * 1000,
      },
    },
  ],
};

// Request payment capability
const paymentRequest: CapabilityRequest = {
  service: "pay.example.com",
  user: "did:sonr:bob456",
  capabilities: [
    {
      resource: "sonr://vault/bob456/wallet",
      actions: ["payment:send"],
      constraints: {
        amount: "100.00",
        frequency: "daily",
        expires: Date.now() + 7 * 24 * 60 * 60 * 1000,
      },
    },
  ],
};

Permission Presentation

Users see human-readable permission requests:

// Convert capability to user dialog
function presentCapability(request: CapabilityRequest): UserDialog {
  const capability = request.capabilities[0];
  const action = capability.actions[0];

  switch (action) {
    case "dwn:read":
      return {
        title: `${request.service} wants to read your data`,
        description: `Access to ${capability.constraints.dataTypes.join(", ")}`,
        icon: "📖",
        risk: "low",
      };

    case "payment:send":
      return {
        title: `${request.service} wants to send payments`,
        description: `Up to $${capability.constraints.amount} ${capability.constraints.frequency}`,
        icon: "💸",
        risk: "medium",
      };
  }
}

Token Generation

UCAN tokens encode delegated permissions:

// Generate UCAN token after user approval
async function generateUCAN(
  issuer: DID,
  audience: string,
  capabilities: Capability[],
): Promise<string> {
  const header = {
    alg: "EdDSA",
    typ: "JWT",
    ucv: "0.10.0",
  };

  const payload = {
    iss: issuer.did,
    aud: audience,
    exp: Math.floor(Date.now() / 1000) + 3600,
    nnc: generateNonce(),
    att: capabilities.map((cap) => ({
      with: cap.resource,
      can: cap.actions,
    })),
  };

  return signJWT(header, payload, issuer.privateKey);
}

Economic Model

Staking Requirements

Services stake SNR tokens for registration:

Service TierMinimum StakeCapabilitiesDaily Limit
Basic1,000 SNRRead operations10,000 requests
Standard5,000 SNRRead/Write operations50,000 requests
Premium10,000 SNRAll operationsUnlimited
Enterprise25,000 SNRCustom capabilitiesUnlimited

Reward Distribution

Services earn rewards for successful operations:

interface RewardParameters {
  baseRate: number; // SNR per authentication
  trustMultiplier: number; // 1.0-3.0x based on score
  volumeBonus: number; // Additional % for volume
}

function calculateMonthlyRewards(
  authentications: number,
  trustScore: number,
  successRate: number,
): number {
  const base = authentications * 0.1; // 0.1 SNR per auth
  const multiplier = 1 + (trustScore / 1000) * 2;
  const bonus = Math.log10(authentications) * 0.01;

  return base * multiplier * (successRate / 100) + bonus;
}

// Example calculation
const rewards = calculateMonthlyRewards(
  50000, // 50k authentications
  900, // Trust score
  99.5, // Success rate
);
// Result: ~2,835 SNR/month

Fee Structure

Transparent pricing for operations:

OperationFeeDistribution
Authentication0.01 SNR70% validators, 20% service, 10% protocol
Capability Request0.001 SNR60% validators, 30% service, 10% protocol
Data Operation0.005 SNR65% validators, 25% service, 10% protocol
Payment Request0.1% of amount50% validators, 40% service, 10% protocol

Integration Patterns

SDK Implementation

Services integrate using the Sonr SDK:

import { SonrService } from "@sonr/service-sdk";

// Initialize service
const service = new SonrService({
  domain: "app.example.com",
  did: "did:sonr:service123",
  capabilities: ["dwn:read", "dwn:write", "payment:request"],
});

// Request authentication
const auth = await service.requestAuth({
  user: "alice@example.com",
  capabilities: {
    "dwn:read": {
      resources: ["profile", "settings"],
      expires: "30d",
    },
  },
});

// Use capabilities
if (auth.success) {
  const profile = await service.vault.read("profile");
  await service.vault.write("settings", newSettings);
}

Web Integration

HTML forms with progressive enhancement:

<!-- Basic form -->
<form action="/api/sonr/auth" method="POST">
  <input type="email" name="user" required />
  <button type="submit">Authenticate</button>
</form>

<!-- Enhanced with HTMX -->
<form hx-post="/api/sonr/auth" hx-target="#result" hx-indicator="#loading">
  <input type="email" name="user" required />
  <select name="capabilities">
    <option value="read">Read Only</option>
    <option value="write">Read/Write</option>
  </select>
  <button type="submit">
    Authenticate
    <span id="loading" class="htmx-indicator">⏳</span>
  </button>
</form>
<div id="result"></div>

Mobile Integration

Native SDKs for iOS and Android:

// iOS Swift
import SonrSDK

let service = SonrService(domain: "app.example.com")

await service.requestAuth(
  capabilities: [.read, .write],
  onSuccess: { token in
    KeychainService.store(token)
    self.navigateToMain()
  }
)
// Android Kotlin
import io.sonr.sdk.SonrService

val service = SonrService("app.example.com")

service.requestAuth(
  capabilities = listOf(Capability.READ, Capability.WRITE),
  onSuccess = { token ->
    secureStorage.putString("auth_token", token)
    startActivity(Intent(this, MainActivity::class.java))
  }
)

Service Discovery

Query Interface

Users find services by capabilities and reputation:

interface ServiceQuery {
  category?: string;
  capabilities?: string[];
  minTrustScore?: number;
  sortBy?: "trust" | "volume" | "age";
}

// Find payment services
const services = await registry.query({
  category: "payment",
  capabilities: ["payment:send"],
  minTrustScore: 800,
  sortBy: "trust",
});

// Service result
interface ServiceInfo {
  domain: string;
  did: string;
  trustScore: number;
  capabilities: string[];
  metrics: {
    totalAuthentications: number;
    successRate: number;
    avgResponseTime: number;
    userSatisfaction: number;
  };
}

Service Categories

Standardized capability categories:

enum ServiceCategory {
  IDENTITY = "identity", // Authentication services
  PAYMENT = "payment", // Financial operations
  STORAGE = "storage", // Data management
  COMPUTE = "compute", // Processing services
  SOCIAL = "social", // Social features
  DEFI = "defi", // DeFi protocols
}

// Standard capabilities per category
const categoryCapabilities = {
  [ServiceCategory.IDENTITY]: ["auth:login", "auth:verify", "auth:2fa"],
  [ServiceCategory.PAYMENT]: [
    "payment:send",
    "payment:receive",
    "payment:exchange",
  ],
  [ServiceCategory.STORAGE]: ["dwn:read", "dwn:write", "dwn:delete"],
};

Compliance Features

Audit Trail

All operations are recorded on-chain:

interface AuthEvent {
  eventId: string;
  timestamp: number;
  service: string; // Service domain
  user: string; // User DID
  action: string; // Operation type
  result: "success" | "failure";
  metadata: {
    ipAddress?: string;
    userAgent?: string;
    location?: string;
  };
}

// Query audit logs
const auditLogs = await registry.queryAuditLogs({
  service: "app.example.com",
  startTime: Date.now() - 86400000, // Last 24 hours
  endTime: Date.now(),
});

Privacy Protection

Zero-knowledge proofs for compliance:

// Prove compliance without revealing details
pub struct ComplianceProof {
    pub has_valid_license: bool,
    pub meets_capital_requirements: bool,
    pub passed_security_audit: bool,
    pub proof: Vec<u8>  // ZK proof
}

impl ComplianceProof {
    pub fn generate(
        license: &License,
        capital: &Capital,
        audit: &SecurityAudit
    ) -> Self {
        // Generate ZK proof
        let proof = zk_prove(&[
            license.is_valid(),
            capital.meets_minimum(),
            audit.passed()
        ]);

        Self {
            has_valid_license: true,
            meets_capital_requirements: true,
            passed_security_audit: true,
            proof
        }
    }
}

Migration Guide

Migration Strategy

Phased approach for existing systems:

interface MigrationPhase {
  duration: string;
  tasks: string[];
  validation: string[];
}

const migrationPlan: MigrationPhase[] = [
  {
    duration: "Week 1-2",
    tasks: [
      "Register service domain",
      "Add DNS verification",
      "Deploy Sonr SDK",
      "Configure dual-auth",
    ],
    validation: [
      "DNS record verified",
      "SDK integration tested",
      "Fallback working",
    ],
  },
  {
    duration: "Week 3-6",
    tasks: [
      "Migrate 10% users",
      "Monitor metrics",
      "Gather feedback",
      "Train support team",
    ],
    validation: [
      "Success rate >99%",
      "User satisfaction maintained",
      "Support tickets handled",
    ],
  },
  {
    duration: "Week 7-12",
    tasks: [
      "Complete migration",
      "Deprecate legacy auth",
      "Archive old data",
      "Update documentation",
    ],
    validation: [
      "All users migrated",
      "Legacy system decommissioned",
      "Cost savings realized",
    ],
  },
];

Compatibility Layer

Support both systems during transition:

class DualAuthProvider {
  async authenticate(request: AuthRequest): Promise<AuthResponse> {
    // Check if user has migrated
    const migrated = await this.checkMigrationStatus(request.userId);

    if (migrated) {
      // Use Sonr authentication
      return await this.sonrAuth.authenticate(request);
    } else {
      // Use legacy authentication
      const result = await this.legacyAuth.authenticate(request);

      // Prompt for migration
      result.migrationPrompt = {
        message: "Upgrade to passwordless authentication?",
        benefits: [
          "No more passwords",
          "Biometric security",
          "Cross-device sync"
        ]
      };

      return result;
    }
  }
}

## Best Practices

### For Service Developers

1. **Start with minimal capabilities**: Request only necessary permissions
2. **Implement proper error handling**: Gracefully handle denials and revocations
3. **Monitor trust metrics**: Track success rates and response times
4. **Maintain high stake**: Higher stakes signal commitment
5. **Document capabilities clearly**: Help users understand requests

### For Validators

1. **Verify DNS records promptly**: Ensure quick service onboarding
2. **Monitor service behavior**: Flag suspicious activities
3. **Participate in slashing votes**: Maintain network integrity
4. **Update trust scores**: Keep reputation metrics current

### For Users

1. **Review capability requests**: Understand what services access
2. **Check trust scores**: Prefer high-reputation services
3. **Revoke unused permissions**: Maintain security hygiene
4. **Report bad behavior**: Help improve the ecosystem

## Next Steps

<Callout title="Ready to Register?" type="success">
**Service Developers**: Start with the [Service Registration Guide](/docs/guides/service-registration) to register your domain.

**Validators**: Learn about [Service Verification](/docs/validators/service-verification) responsibilities.

**Users**: Understand [Permission Management](/docs/users/permissions) in your Vault.
</Callout>

<Cards>
  <Card title="Service Module" href="/docs/reference/modules/x-svc">
    Technical specifications for service registry
  </Card>
  <Card title="UCAN Module" href="/docs/reference/modules/x-ucan">
    Capability delegation implementation
  </Card>
  <Card title="DWN Integration" href="/docs/reference/modules/x-dwn">
    Vault interaction patterns
  </Card>
  <Card title="Migration Examples" href="/docs/examples/auth-migration">
    Real-world migration case studies
  </Card>
</Cards>