@aiam/ciba 0.8.5 → 0.8.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/ciba.mjs +18 -26
  2. package/package.json +1 -1
package/ciba.mjs CHANGED
@@ -439,22 +439,10 @@ function startDaemon(provider, deviceDoc, privateKey, serverUrl) {
439
439
  const requests = deviceDoc.getMap('requests');
440
440
  const resourcesMap = deviceDoc.getMap('resources');
441
441
 
442
+ // Pass attrs straight through — server resolves grant_type from resource URN.
442
443
  const attrs = { ...(req.attrs || {}) };
443
- const resourceUrn = attrs.resource;
444
- if (!attrs.grant_type && typeof resourceUrn === 'string') {
445
- if (resourceUrn.startsWith('urn:sap:destination:')) {
446
- attrs.grant_type = 'urn:sap:destination';
447
- if (!attrs.destination) attrs.destination = resourceUrn.slice('urn:sap:destination:'.length);
448
- } else if (resourceUrn.startsWith('urn:sap:identity:') || resourceUrn.startsWith('urn:ietf:params:oauth:resource:')) {
449
- attrs.grant_type = 'urn:ietf:params:oauth:grant-type:jwt-bearer';
450
- }
451
- }
452
-
453
444
  const defaultResource = `urn:sap:destination:${process.env.CIBA_DEFAULT_DESTINATION || 'WEBAGENTS_BACKEND'}`;
454
- const requestedResource =
455
- attrs.grant_type === 'urn:sap:destination' && attrs.destination
456
- ? `urn:sap:destination:${attrs.destination}`
457
- : attrs.resource ?? defaultResource;
445
+ const requestedResource = attrs.resource ?? defaultResource;
458
446
 
459
447
  const decryptFromTokenMap = (tokenMap) => {
460
448
  const ciphertext = tokenMap.get('ciphertext');
@@ -466,14 +454,8 @@ function startDaemon(provider, deviceDoc, privateKey, serverUrl) {
466
454
  };
467
455
 
468
456
  if (req.command === 'refresh') {
469
- // Fire-and-forget: write the request, return immediately.
470
- // Server exchanges async; result lands on device doc via Yjs.
471
- // Default to the same resource as `ciba token` when none specified.
472
- if (!attrs.grant_type && !attrs.resource && !attrs.destination) {
473
- attrs.resource = `urn:sap:destination:${process.env.CIBA_DEFAULT_DESTINATION || 'WEBAGENTS_BACKEND'}`;
474
- attrs.grant_type = 'urn:sap:destination';
475
- attrs.destination = process.env.CIBA_DEFAULT_DESTINATION || 'WEBAGENTS_BACKEND';
476
- }
457
+ // Fire-and-forget just set default resource if none given.
458
+ if (!attrs.resource) attrs.resource = defaultResource;
477
459
  const newRid = randomBytes(8).toString('base64url');
478
460
  dlog(`refresh; writing requests[${newRid}] attrs=${JSON.stringify(attrs)}`);
479
461
  requests.set(newRid, { ...attrs, status: 'pending', created_at: new Date().toISOString() });
@@ -486,18 +468,28 @@ function startDaemon(provider, deviceDoc, privateKey, serverUrl) {
486
468
  if (cachedName) {
487
469
  const cachedMap = deviceDoc.getMap(cachedName);
488
470
  const exp = cachedMap.get('exp');
489
- if (exp && exp > Math.floor(Date.now() / 1000) + 60) {
471
+ const now = Math.floor(Date.now() / 1000);
472
+ // Return cached token if: no exp set (server manages expiry),
473
+ // or exp is still valid. Only skip if we know it's expired.
474
+ const isExpired = exp && exp < now + 60;
475
+ if (!isExpired) {
490
476
  const token = decryptFromTokenMap(cachedMap);
491
477
  if (token) { conn.end(JSON.stringify({ token })); return; }
492
478
  }
493
479
  }
494
480
 
481
+ const prevTokenMapName = resourcesMap.get(requestedResource);
495
482
  const newRid = randomBytes(8).toString('base64url');
496
- dlog(`cache miss; writing requests[${newRid}] attrs=${JSON.stringify(attrs)}`);
483
+ dlog(`cache miss; writing requests[${newRid}] attrs=${JSON.stringify(attrs)} resources=${JSON.stringify([...resourcesMap.entries()])}`);
497
484
  requests.set(newRid, { ...attrs, status: 'pending', created_at: new Date().toISOString() });
498
485
 
499
- dlog(`resources map: ${JSON.stringify([...resourcesMap.entries()])} requested=${requestedResource}`);
500
- const prevTokenMapName = resourcesMap.get(requestedResource);
486
+ // Immediate re-check: token may have landed between cache check and now.
487
+ const postWriteName = resourcesMap.get(requestedResource);
488
+ if (postWriteName && postWriteName !== prevTokenMapName) {
489
+ const m = deviceDoc.getMap(postWriteName);
490
+ const token = decryptFromTokenMap(m);
491
+ if (token) { conn.end(JSON.stringify({ token })); return; }
492
+ }
501
493
  const newTokenMap = deviceDoc.getMap(`token:${newRid}`);
502
494
 
503
495
  const viaRid = firstInYMap(newTokenMap, (key) => key === 'ciphertext' || key === 'error', 30_000)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiam/ciba",
3
- "version": "0.8.5",
3
+ "version": "0.8.7",
4
4
  "description": "OAuth 2.0 Device Authorization Grant CLI with cross-device push approval (Yjs sync, ECDH-encrypted token delivery, persistent device id)",
5
5
  "type": "module",
6
6
  "bin": {