Your First Attestation

First Attestation

Step-by-step guide to completing your first device attestation with Grantiva.

Prerequisites

  • Grantiva account created
  • iOS app with Grantiva SDK integrated
  • Backend server configured to validate JWT tokens
  • Physical iOS device (iOS 14.0+)

Step 1: Verify Setup

iOS App Checklist

// AppDelegate.swift or App.swift
import Grantiva
import DeviceCheck

// Verify App Attest is available
if DCAppAttestService.shared.isSupported {
    print("✅ App Attest is supported")
} else {
    print("❌ App Attest not supported on this device")
}

Server Checklist

// Verify JWT secret is configured
console.log('JWT Secret configured:', !!process.env.GRANTIVA_JWT_SECRET);

// Test endpoint
app.get('/api/test-auth', authenticateToken, (req, res) => {
    res.json({ 
        status: 'authenticated',
        deviceId: req.user.sub,
        riskScore: req.user.deviceIntelligence.riskScore
    });
});

Step 2: Implement Attestation Flow

iOS Implementation

import SwiftUI
import Grantiva

struct ContentView: View {
    @State private var attestationStatus = "Not Started"
    @State private var jwtToken: String?
    @State private var riskScore: Int?
    @State private var isLoading = false
    
    private let grantiva = Grantiva()
    
    var body: some View {
        VStack(spacing: 20) {
            Text("Grantiva Attestation Demo")
                .font(.title)
            
            VStack(alignment: .leading, spacing: 10) {
                Label("Status: \(attestationStatus)", systemImage: statusIcon)
                
                if let score = riskScore {
                    Label("Risk Score: \(score)/100", systemImage: "shield")
                }
                
                if jwtToken != nil {
                    Label("Token: Received ✅", systemImage: "key")
                }
            }
            .padding()
            .background(Color.gray.opacity(0.1))
            .cornerRadius(10)
            
            Button(action: performAttestation) {
                if isLoading {
                    ProgressView()
                        .progressViewStyle(CircularProgressViewStyle())
                } else {
                    Text("Start Attestation")
                }
            }
            .buttonStyle(.borderedProminent)
            .disabled(isLoading)
            
            if jwtToken != nil {
                Button("Test Authenticated API Call") {
                    testAuthenticatedCall()
                }
                .buttonStyle(.bordered)
            }
        }
        .padding()
    }
    
    private var statusIcon: String {
        switch attestationStatus {
        case "Success": return "checkmark.circle.fill"
        case "Failed": return "xmark.circle.fill"
        default: return "circle"
        }
    }
    
    private func performAttestation() {
        isLoading = true
        attestationStatus = "Attesting..."
        
        Task {
            do {
                // Perform attestation
                let result = try await grantiva.validateAttestation()
                
                await MainActor.run {
                    if result.isValid {
                        attestationStatus = "Success"
                        jwtToken = result.token
                        riskScore = result.deviceIntelligence.riskScore
                        
                        // Store token for API calls
                        UserDefaults.standard.set(result.token, forKey: "attestation_token")
                        
                        print("Attestation successful!")
                        print("Device ID: \(result.deviceIntelligence.deviceId)")
                        print("Risk Score: \(result.deviceIntelligence.riskScore)")
                        print("Jailbreak Detected: \(result.deviceIntelligence.jailbreakDetected)")
                    } else {
                        attestationStatus = "Failed"
                    }
                    isLoading = false
                }
            } catch {
                await MainActor.run {
                    attestationStatus = "Failed: \(error.localizedDescription)"
                    isLoading = false
                }
            }
        }
    }
    
    private func testAuthenticatedCall() {
        guard let token = jwtToken else { return }
        
        Task {
            var request = URLRequest(url: URL(string: "https://api.yourapp.com/api/test-auth")!)
            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
            
            do {
                let (data, _) = try await URLSession.shared.data(for: request)
                let response = try JSONDecoder().decode(TestResponse.self, from: data)
                print("API Response: \(response)")
            } catch {
                print("API call failed: \(error)")
            }
        }
    }
}

struct TestResponse: Codable {
    let status: String
    let deviceId: String
    let riskScore: Int
}

Step 3: Run Your First Attestation

  1. Build and run on a real device

    Connect your iPhone and select it as the run destination in Xcode

  2. Tap "Start Attestation"

    The attestation process will begin

  3. Monitor the console output

    You'll see detailed logs about the attestation process

  4. Check the results

    View your risk score and attestation status

Step 4: Verify in Dashboard

After successful attestation, you can verify the device in your Grantiva dashboard:

  1. Log in to your Grantiva dashboard
  2. Navigate to Analytics → Devices
  3. Find your device by its ID or attestation time
  4. View detailed device intelligence and risk analysis

Common Issues and Solutions

App Attest Not Supported

Error: DCAppAttestService.shared.isSupported returns false

Solution: Ensure you're testing on a real device with iOS 14.0+ and in a supported region

Network Error

Error: Failed to connect to Grantiva servers

Solution: Check internet connection and ensure your bundle ID is registered in Grantiva

Invalid Bundle ID

Error: Bundle ID mismatch

Solution: Verify your app's bundle ID matches what's configured in your Grantiva account

JWT Validation Failed

Error: 403 Forbidden on API calls

Solution: Ensure your server has the correct JWT secret configured

Understanding Your Results

Risk Scores

  • 0-20: Low risk - Normal device with no suspicious indicators
  • 21-50: Medium risk - Some anomalies detected, monitor closely
  • 51-75: High risk - Multiple risk factors present
  • 76-100: Critical risk - Strong indicators of compromise

Device Intelligence Factors

  • Jailbreak detection status
  • App integrity verification
  • Device consistency checks
  • Historical attestation patterns
  • Geographic anomalies

Next Steps

Congratulations! You've completed your first attestation. Here's what to do next: