|
| 1 | +--- |
| 2 | +sidebar_position: 2 |
| 3 | +title: Official SDK Guidelines |
| 4 | +description: Official guidelines and standards for implementing OpenTDF SDKs |
| 5 | +--- |
| 6 | + |
| 7 | +# Official SDK Guidelines |
| 8 | + |
| 9 | +This document provides the official guidelines and standards for: |
| 10 | +- OpenTDF contributors implementing new language SDKs |
| 11 | +- Developers who want to understand the official SDK architecture and implementation details |
| 12 | + |
| 13 | +If you're looking to *use* an existing OpenTDF SDK, please see the [SDK Overview](/sdks/overview) instead. |
| 14 | + |
| 15 | +## Core Principles for Official OpenTDF SDKs |
| 16 | + |
| 17 | +All official OpenTDF SDKs must adhere to these core principles to ensure functional parity and consistent developer experience across languages: |
| 18 | + |
| 19 | +### 1. Platform-First Initialization |
| 20 | + |
| 21 | +Every SDK requires a platform base URL (endpoint) at initialization, along with necessary credentials. This endpoint is the entry point to OpenTDF platform services. The SDK will automatically: |
| 22 | + |
| 23 | +- Discover service endpoints (KAS, Policy, etc.) |
| 24 | +- Configure network clients |
| 25 | +- Retrieve well-known configuration |
| 26 | + |
| 27 | +### 2. Service Communication via Generated Clients |
| 28 | + |
| 29 | +SDKs use auto-generated API clients (using Protocol Buffers/Connect RPC) for communicating with OpenTDF services. This ensures: |
| 30 | + |
| 31 | +- Consistent interfaces across languages |
| 32 | +- Type-safe API calls |
| 33 | +- Reduced boilerplate code |
| 34 | +- Up-to-date API definitions |
| 35 | + |
| 36 | +### 3. Format Support and Cryptography |
| 37 | + |
| 38 | +Every SDK must support: |
| 39 | + |
| 40 | +- Standard TDF (ZIP/JSON format) with manifest |
| 41 | +- NanoTDF (compact binary format) |
| 42 | +- Attribute-Based Access Control (ABAC) |
| 43 | +- Signed assertions and policy binding |
| 44 | + |
| 45 | +### 4. Language-Idiomatic Design |
| 46 | + |
| 47 | +While maintaining functional parity, each SDK should follow patterns natural to its language: |
| 48 | + |
| 49 | +#### Go SDK (Reference Implementation) |
| 50 | +```go |
| 51 | +// Functional options pattern |
| 52 | +client := tdf.NewClient( |
| 53 | + WithPlatformURL("https://platform.example.com"), |
| 54 | + WithClientCredentials("id", "secret"), |
| 55 | +) |
| 56 | +``` |
| 57 | + |
| 58 | +#### Java SDK |
| 59 | +```java |
| 60 | +// Builder pattern |
| 61 | +TdfClient client = TdfClient.builder() |
| 62 | + .platformUrl("https://platform.example.com") |
| 63 | + .clientCredentials("id", "secret") |
| 64 | + .build(); |
| 65 | +``` |
| 66 | + |
| 67 | +#### JavaScript/TypeScript SDK |
| 68 | +```typescript |
| 69 | +// Options object pattern |
| 70 | +const client = new TdfClient({ |
| 71 | + platformUrl: "https://platform.example.com", |
| 72 | + credentials: { |
| 73 | + clientId: "id", |
| 74 | + clientSecret: "secret" |
| 75 | + } |
| 76 | +}); |
| 77 | +``` |
| 78 | + |
| 79 | +## Unified Interface Strategy |
| 80 | + |
| 81 | +### Java SDK Implementation |
| 82 | + |
| 83 | +The Java SDK should provide a clean, unified interface through the new `TdfClient` class: |
| 84 | + |
| 85 | +```java |
| 86 | +// Future unified API |
| 87 | +TdfClient client = TdfClient.builder() |
| 88 | + .platformUrl("https://platform.example.com") |
| 89 | + .clientCredentials("id", "secret") |
| 90 | + .build(); |
| 91 | + |
| 92 | +// Encrypt with data attributes |
| 93 | +client.setDataAttributes(List.of("attr1", "attr2")); |
| 94 | +client.addAssertion("classification", "SECRET", signingKey); |
| 95 | + |
| 96 | +// Encrypt/decrypt methods support both formats |
| 97 | +try (InputStream in = new FileInputStream("plain.txt"); |
| 98 | + OutputStream out = new FileOutputStream("encrypted.tdf")) { |
| 99 | + client.encrypt(in, out, TdfClient.Format.TDF); // or Format.NANO |
| 100 | +} |
| 101 | +``` |
| 102 | + |
| 103 | +### Web SDK Implementation |
| 104 | + |
| 105 | +The Web SDK should provide a similar unified interface through TypeScript: |
| 106 | + |
| 107 | +```typescript |
| 108 | +const client = new TdfClient({ |
| 109 | + platformUrl: "https://platform.example.com", |
| 110 | + oidcOrigin: "https://idp.example.com", |
| 111 | + credentials: { |
| 112 | + clientId: "myClientId", |
| 113 | + clientSecret: "secretToken" |
| 114 | + } |
| 115 | +}); |
| 116 | + |
| 117 | +// Set policy and assertions |
| 118 | +await client.setDataAttributes(["https://opentdf.io/attr/class/value/secret"]); |
| 119 | +await client.addAssertion("clearance", "SECRET", signingKey); |
| 120 | + |
| 121 | +// Encrypt data (automatically selects format based on size/config) |
| 122 | +const ciphertext = await client.encrypt(plaintext, { format: "nano" }); |
| 123 | +const decrypted = await client.decrypt(ciphertext); // auto-detects format |
| 124 | +``` |
| 125 | + |
| 126 | +## Migration Strategy |
| 127 | + |
| 128 | +Here's how to migrate existing code to the new unified interface: |
| 129 | + |
| 130 | +### 1. Client Initialization Migration |
| 131 | + |
| 132 | +**Old approach (pre-4.0):** |
| 133 | +```typescript |
| 134 | +// JavaScript/TypeScript |
| 135 | +const client = await NanoTDFClient.fromConfig({ |
| 136 | + kasUrl: "https://kas.example.com", |
| 137 | + authProvider: new OIDCCredentials(/*...*/) |
| 138 | +}); |
| 139 | + |
| 140 | +// Java |
| 141 | +NanoTDFClient client = new NanoTDFClient(); |
| 142 | +client.setKasUrl("https://kas.example.com"); |
| 143 | +client.setAuthProvider(new OIDCCredentials()); |
| 144 | +``` |
| 145 | + |
| 146 | +**New unified approach (4.0+):** |
| 147 | +```typescript |
| 148 | +// JavaScript/TypeScript |
| 149 | +const client = new TdfClient({ |
| 150 | + platformUrl: "https://platform.example.com", // Single endpoint |
| 151 | + credentials: { |
| 152 | + clientId: "id", |
| 153 | + clientSecret: "secret" |
| 154 | + } |
| 155 | +}); |
| 156 | + |
| 157 | +// Java |
| 158 | +TdfClient client = TdfClient.builder() |
| 159 | + .platformUrl("https://platform.example.com") |
| 160 | + .clientCredentials("id", "secret") |
| 161 | + .build(); |
| 162 | +``` |
| 163 | + |
| 164 | +### 2. Encryption/Decryption Migration |
| 165 | + |
| 166 | +**Old approach:** |
| 167 | + |
| 168 | +```typescript |
| 169 | +// JavaScript/TypeScript - separate clients for different formats |
| 170 | +const nanoClient = new NanoTDFClient(config); |
| 171 | +const tdfClient = new TDFClient(config); |
| 172 | + |
| 173 | +const nanoEncrypted = await nanoClient.encrypt(data); |
| 174 | +const tdfEncrypted = await tdfClient.encrypt(data); |
| 175 | + |
| 176 | +// Java |
| 177 | +NanoTDFClient nanoClient = new NanoTDFClient(); |
| 178 | +TDFClient tdfClient = new TDFClient(); |
| 179 | + |
| 180 | +byte[] nanoEncrypted = nanoClient.encrypt(data); |
| 181 | +byte[] tdfEncrypted = tdfClient.encrypt(data); |
| 182 | +``` |
| 183 | + |
| 184 | +**New unified approach:** |
| 185 | +```typescript |
| 186 | +// JavaScript/TypeScript - single client handles both formats |
| 187 | +const client = new TdfClient(config); |
| 188 | + |
| 189 | +// Format is auto-selected or explicitly specified |
| 190 | +const encrypted = await client.encrypt(data, { format: "nano" }); |
| 191 | +const decrypted = await client.decrypt(encrypted); // Format auto-detected |
| 192 | + |
| 193 | +// Java |
| 194 | +TdfClient client = TdfClient.builder().build(); |
| 195 | + |
| 196 | +// Streaming API with format selection |
| 197 | +try (InputStream in = new FileInputStream("plain.txt"); |
| 198 | + OutputStream out = new FileOutputStream("encrypted.tdf")) { |
| 199 | + client.encrypt(in, out, TdfClient.Format.NANO); |
| 200 | +} |
| 201 | +``` |
| 202 | + |
| 203 | +### 3. Testing Migration |
| 204 | + |
| 205 | +Replace abstract test suites with concrete integration tests: |
| 206 | + |
| 207 | +```typescript |
| 208 | +describe('TDF Client Migration', () => { |
| 209 | + // Test unified client with legacy format |
| 210 | + it('should decrypt legacy NanoTDF format', async () => { |
| 211 | + const unified = new TdfClient(config); |
| 212 | + const legacyEncrypted = await getLegacyEncryptedData(); |
| 213 | + const decrypted = await unified.decrypt(legacyEncrypted); |
| 214 | + expect(decrypted).toEqual(originalData); |
| 215 | + }); |
| 216 | + |
| 217 | + // Test format interoperability |
| 218 | + it('should support cross-format operations', async () => { |
| 219 | + const client = new TdfClient(config); |
| 220 | + |
| 221 | + // Encrypt as NanoTDF |
| 222 | + const nano = await client.encrypt(data, { format: 'nano' }); |
| 223 | + |
| 224 | + // Decrypt with format auto-detection |
| 225 | + const decrypted1 = await client.decrypt(nano); |
| 226 | + expect(decrypted1).toEqual(data); |
| 227 | + |
| 228 | + // Encrypt as standard TDF |
| 229 | + const tdf = await client.encrypt(data, { format: 'tdf' }); |
| 230 | + |
| 231 | + // Decrypt with format auto-detection |
| 232 | + const decrypted2 = await client.decrypt(tdf); |
| 233 | + expect(decrypted2).toEqual(data); |
| 234 | + }); |
| 235 | +}); |
| 236 | +``` |
| 237 | + |
| 238 | +### Migration Gotchas |
| 239 | + |
| 240 | +1. **Attribute Format Changes** |
| 241 | + - Legacy: Simple strings (`"SECRET"`) |
| 242 | + - New: Full URIs (`"https://opentdf.io/attr/classification/value/secret"`) |
| 243 | + - Migration helper: `client.normalizeAttribute(legacyAttr)` |
| 244 | + |
| 245 | +2. **Error Handling Changes** |
| 246 | + - Legacy: Multiple error types (`NanoTDFError`, `TDFError`) |
| 247 | + - New: Unified `TdfError` with error codes |
| 248 | + - Example: `TdfError.FORMAT_INVALID` instead of `InvalidNanoTDFError` |
| 249 | + |
| 250 | +3. **Configuration Changes** |
| 251 | + - Legacy configs won't work with unified client |
| 252 | + - Use `ConfigMigrationTool` (included) to convert: |
| 253 | + ```typescript |
| 254 | + const unifiedConfig = ConfigMigrationTool.migrate(legacyConfig); |
| 255 | + const client = new TdfClient(unifiedConfig); |
| 256 | + ``` |
| 257 | + |
| 258 | +## Implementing a New SDK |
| 259 | + |
| 260 | +### Prerequisites |
| 261 | + |
| 262 | +1. Familiarize yourself with: |
| 263 | + - [OpenTDF Architecture](/architecture) |
| 264 | + - [TDF Specification](https://github.com/opentdf/spec) |
| 265 | + - [Go SDK](https://github.com/opentdf/platform) (reference implementation) |
| 266 | + |
| 267 | +2. Required capabilities: |
| 268 | + - Protocol Buffers / Connect RPC support |
| 269 | + - Modern cryptography library support |
| 270 | + - ZIP handling (for standard TDF) |
| 271 | + - JSON parsing |
| 272 | + |
| 273 | +### Implementation Steps |
| 274 | + |
| 275 | +1. **Service Client Generation** |
| 276 | + - Generate API clients from Protocol Buffer definitions |
| 277 | + - Implement authentication flow |
| 278 | + - Configure service discovery |
| 279 | + |
| 280 | +2. **Core Cryptographic Operations** |
| 281 | + - Implement key derivation |
| 282 | + - Support ECC for NanoTDF |
| 283 | + - Implement signature verification |
| 284 | + |
| 285 | +3. **Format Support** |
| 286 | + - Implement TDF manifest creation/parsing |
| 287 | + - Implement NanoTDF binary format |
| 288 | + - Support streaming for large files |
| 289 | + |
| 290 | +4. **Policy and Assertions** |
| 291 | + - Implement ABAC policy binding |
| 292 | + - Support signed assertions |
| 293 | + - Validate integrity during decryption |
| 294 | + |
| 295 | +## Implementation Checklist |
| 296 | + |
| 297 | +For each new SDK implementation: |
| 298 | + |
| 299 | +- [ ] Service Integration |
| 300 | + - [ ] Platform URL configuration |
| 301 | + - [ ] Well-known endpoint discovery |
| 302 | + - [ ] Authentication flow |
| 303 | + - [ ] Generated service clients |
| 304 | + |
| 305 | +- [ ] TDF Support |
| 306 | + - [ ] Manifest creation/parsing |
| 307 | + - [ ] ZIP packaging |
| 308 | + - [ ] Streaming support |
| 309 | + - [ ] Policy binding |
| 310 | + |
| 311 | +- [ ] NanoTDF Support |
| 312 | + - [ ] Binary format handling |
| 313 | + - [ ] ECC cryptography |
| 314 | + - [ ] Performance optimization |
| 315 | + |
| 316 | +- [ ] Policy & Security |
| 317 | + - [ ] ABAC implementation |
| 318 | + - [ ] Assertion signing/verification |
| 319 | + - [ ] Key derivation |
| 320 | + - [ ] Integrity validation |
| 321 | + |
| 322 | +For detailed technical specifications and implementation guidance, see: |
| 323 | +- [TDF Format Specification](/spec/schema/opentdf) |
| 324 | +- [NanoTDF Specification](/spec/schema/nanotdf) |
| 325 | +- [Protocol Documentation](/spec/protocol) |
0 commit comments