fix(jwt): app-scoped user account fallback + HMAC-parity response shape with FK expansion#88
Merged
Merged
Conversation
JwtEndpoint::login required user->kyte_account != 0 to proceed. That holds for the default KyteUser model but NOT for app-scoped User models created via Shipyard DataModel — those users belong to the Application, and the Application carries the kyte_account FK. Result: login on apps with custom user_model returned 401 even for valid credentials. STEP3 (accountId === 0) bailed before token issuance, despite STEP1 user retrieve + STEP2 password_verify both passing. Fix: if user->kyte_account is missing/0 and app context is set, fall back to app->kyte_account. Mirrors how HMAC derives account context from the app for session-on-app flows. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
JWT /jwt/login was returning only the tokens. HMAC /Session also
returns uid, account_id, and data (user object array with protected
fields stripped) — customer apps consuming the response (e.g.
session.data[0].organization_type) silently fail under JWT because
the payload was missing.
Add to JWT login response:
- uid: user.id
- account_id: account.id
- data: user data with protected fields ('' replaced),
wrapped per USE_SESSION_MAP (array vs object) to
match HMAC SessionController::new behavior
Intentionally NOT included:
- kyte_pub / kyte_iden / kyte_num — HMAC-only API handoff creds
(JWT has no handoff concept; access_token is the credential)
- session / token — HMAC-only sessionToken / txToken
- session_created — derivable from access token iat claim
New userToArray() helper standalone-replicates the protected-field
stripping from ModelController::getObject without requiring a
controller context.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… parity)
HMAC SessionController sets getFKTables = SESSION_RETURN_FK (default
true), causing getObject() to recursively expand FK integers into
full nested objects. JWT userToArray was returning raw FK ints, so
frontend code like 'user.org.org_type' silently failed (org was '2',
not {id:2, org_type:'LP'}).
Add FK expansion to userToArray:
- Walk model struct
- For fields with 'fk' definition + non-empty value, retrieve the
referenced ModelObject and recursively serialize it
- Bounded at depth 3 to prevent runaway recursion on cyclic FKs
Respects SESSION_RETURN_FK constant (defaults true, can be disabled
per-deployment). retrieve() handles dbswitch automatically based on
the FK model's appId, so app-scoped + default-scoped FKs both work.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three related fixes for JWT login on apps with a custom user_model. Verified end-to-end on dev (device 19) via dev-branch composer pinning before tagging.
Commits
user.org→{id:2, org_type:'LP', ...}). JWT was returning raw FK ints. Recursively expand bounded at depth 3.Test plan
user_model='User', app-scoped FKorg, and frontend code consuminguser.org.org_typedev-fix/jwt-app-scoped-account as 4.4.x-dev) — only host that received changes pre-mergeKnown follow-up
FK expansion is N+1 per login. Tempo card #171 for optimization (eager-loading hook OR per-user cache for access-token TTL).
Patch v4.4.5. No schema changes.
🤖 Generated with Claude Code