{
  "info": { "name": "SReverse complete workflow demonstration", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", "description": "Synthetic local workflow. Public test credentials only." },
  "variable": [
    { "key": "base", "value": "http://127.0.0.1:8787" },
    { "key": "access_token", "value": "" }, { "key": "refresh_token", "value": "" }
  ],
  "item": [
    { "name": "Login", "event": [{ "listen": "test", "script": { "exec": ["const data = pm.response.json();", "pm.collectionVariables.set('access_token', data.access_token);", "pm.collectionVariables.set('refresh_token', data.refresh_token);", "pm.test('login succeeds', () => pm.response.to.have.status(200));"] } }], "request": { "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }], "body": { "mode": "raw", "raw": "{\"username\":\"demo\",\"password\":\"demo\"}" }, "url": "{{base}}/v1/login" } },
    { "name": "Rotate refresh token", "event": [{ "listen": "test", "script": { "exec": ["const data = pm.response.json();", "pm.collectionVariables.set('access_token', data.access_token);", "pm.collectionVariables.set('refresh_token', data.refresh_token);", "pm.test('refresh token rotates', () => { pm.response.to.have.status(200); pm.expect(data.refresh_token).to.eql('refresh-2'); });"] } }], "request": { "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }], "body": { "mode": "raw", "raw": "{\"refresh_token\":\"{{refresh_token}}\"}" }, "url": "{{base}}/v1/refresh" } },
    { "name": "Encrypted signed lookup", "event": [{ "listen": "prerequest", "script": { "exec": ["const enc = new TextEncoder();", "const to64 = bytes => btoa(String.fromCharCode(...bytes));", "const toHex = bytes => Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');", "const aesKey = await crypto.subtle.importKey('raw', new Uint8Array([...Array(32).keys()]), 'AES-GCM', false, ['encrypt']);", "const iv = crypto.getRandomValues(new Uint8Array(12));", "const encrypted = new Uint8Array(await crypto.subtle.encrypt({name:'AES-GCM', iv}, aesKey, enc.encode(JSON.stringify({reference:'ABC123'}))));", "const body = JSON.stringify({iv:to64(iv), ciphertext:to64(encrypted)});", "const ts = String(Math.floor(Date.now()/1000));", "const nonce = pm.variables.replaceIn('{{$guid}}');", "const canonical = `POST\\n/v1/lookup\\n${ts}\\n${nonce}\\n${body}`;", "const hmacKey = await crypto.subtle.importKey('raw', enc.encode('sreverse-public-demo-signing-key'), {name:'HMAC', hash:'SHA-256'}, false, ['sign']);", "const sig = toHex(new Uint8Array(await crypto.subtle.sign('HMAC', hmacKey, enc.encode(canonical))));", "pm.variables.set('lookup_body', body); pm.variables.set('timestamp', ts); pm.variables.set('nonce', nonce); pm.variables.set('signature', sig);"] } }, { "listen": "test", "script": { "exec": ["pm.test('lookup succeeds', () => pm.response.to.have.status(200));", "pm.test('response is parsed', () => pm.expect(pm.response.json().reference).to.eql('ABC123'));"] } }], "request": { "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }, { "key": "Authorization", "value": "Bearer {{access_token}}" }, { "key": "X-Timestamp", "value": "{{timestamp}}" }, { "key": "X-Nonce", "value": "{{nonce}}" }, { "key": "X-Signature", "value": "{{signature}}" }], "body": { "mode": "raw", "raw": "{{lookup_body}}" }, "url": "{{base}}/v1/lookup" } },
    { "name": "Bad signature is rejected", "request": { "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }, { "key": "Authorization", "value": "Bearer {{access_token}}" }, { "key": "X-Timestamp", "value": "{{timestamp}}" }, { "key": "X-Nonce", "value": "{{nonce}}" }, { "key": "X-Signature", "value": "bad" }], "body": { "mode": "raw", "raw": "{{lookup_body}}" }, "url": "{{base}}/v1/lookup" }, "event": [{ "listen": "test", "script": { "exec": ["pm.test('bad signature is rejected', () => pm.response.to.have.status(403));"] } }] }
  ]
}
