Summary
src/oauth-handler.ts:608-624 mints grants with props: {userId, email, name, scopes}. No tenantId, no tier. Every initialize call has to re-resolve tenant from edge-auth via provisionTenant(userId).
Why this matters
Defense-in-depth. Any drift between provisioning time and session init time causes inconsistent behavior. Observable symptom from the img-forge/billing diagnostic:
- D1 shows tenant
tenant-admin-default with tier='team'
- Fresh
scaffold_create receipt returns tier: "free"
That's almost certainly a stale session blob returning the tier it saw at grant mint, not the current tier in D1. If we baked tenantId and tier into grant props at consent time, sessions can't drift because they always re-init on fresh grant.
Proposed fix
At oauth-handler.ts:608-624 where completeAuthorization is called:
```ts
// Resolve the full identity chain before minting the grant
const { tenantId, tier } = await env.AUTH_SERVICE.provisionTenant({
userId,
source: 'oauth',
});
await completeAuthorization({
userId,
scope,
props: { userId, email, name, scopes, tenantId, tier }, // ← add tenantId + tier
});
```
Session init at gateway.ts:1293-1301 then reads tenantId and tier directly from props instead of re-calling provisionTenant.
Severity
Low / defense-in-depth. Not blocking anything right now. The kind of latent drift that bites during incidents.
Related
Surfaced during the img-forge stackbilt_credits billing investigation (see Stackbilt-dev/edge-auth billing issue).
Summary
src/oauth-handler.ts:608-624mints grants withprops: {userId, email, name, scopes}. NotenantId, notier. Everyinitializecall has to re-resolve tenant from edge-auth viaprovisionTenant(userId).Why this matters
Defense-in-depth. Any drift between provisioning time and session init time causes inconsistent behavior. Observable symptom from the img-forge/billing diagnostic:
tenant-admin-defaultwith tier='team'scaffold_createreceipt returnstier: "free"That's almost certainly a stale session blob returning the tier it saw at grant mint, not the current tier in D1. If we baked
tenantIdandtierinto grant props at consent time, sessions can't drift because they always re-init on fresh grant.Proposed fix
At
oauth-handler.ts:608-624wherecompleteAuthorizationis called:```ts
// Resolve the full identity chain before minting the grant
const { tenantId, tier } = await env.AUTH_SERVICE.provisionTenant({
userId,
source: 'oauth',
});
await completeAuthorization({
userId,
scope,
props: { userId, email, name, scopes, tenantId, tier }, // ← add tenantId + tier
});
```
Session init at
gateway.ts:1293-1301then readstenantIdandtierdirectly from props instead of re-callingprovisionTenant.Severity
Low / defense-in-depth. Not blocking anything right now. The kind of latent drift that bites during incidents.
Related
Surfaced during the img-forge
stackbilt_creditsbilling investigation (seeStackbilt-dev/edge-authbilling issue).