Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
## 4.4.3

### Bug Fix: `/jwt/login` fatals on apps with custom `user_model`

When an Application's `user_model` is set to an app-specific DataModel (e.g. `"User"` rather than the default `"KyteUser"`), `JwtEndpoint::resolveAuthContext` called `constant($app->user_model)` to resolve the model definition. But the JWT endpoint dispatches *before* `Api::loadAppModels()` runs in the normal MVC pipeline, so the app-scoped constant wasn't yet defined. In PHP 8+ that's a fatal: `Undefined constant "User"`. Surface to the client was HTTP 500.

HMAC `/Session` login did not hit this because `Api::route()` calls `loadAppModels` before reaching the session controller. JWT's whole point is to bypass that pipeline (login can't require auth), which is what created the gap.

Fix: `resolveAuthContext` now calls `Api::loadAppModels($app)` immediately after retrieving the Application, before referencing the constant. If the app references a name that no DataModel row defines, falls back to `KyteUser` (with an `error_log` breadcrumb) rather than fatal — login then naturally fails at `password_verify`, which is a safer surface than a 500.

No schema changes. Composer upgrade is sufficient.

## 4.4.2

### Bug Fix: ErrorHandler crash when `apiContext->key` is a ModelObject
Expand Down
21 changes: 21 additions & 0 deletions src/Core/Auth/JwtEndpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,27 @@ private static function resolveAuthContext(?string $appIdentifier): array
}

if ($app->user_model !== null && $app->username_colname !== null && $app->password_colname !== null) {
// App-specific DataModel constants ("User", "Customer", etc.) are
// registered lazily by Api::loadAppModels when an app context is
// detected in the normal MVC pipeline. JwtEndpoint dispatches
// BEFORE that pipeline runs, so the constant we want may not
// exist yet. Load explicitly to make the constant available.
\Kyte\Core\Api::loadAppModels($app);

if (!defined($app->user_model)) {
// loadAppModels couldn't define it (no matching DataModel
// row, or the row references a name that wasn't registered).
// Fall back to KyteUser rather than fatal — login will then
// fail at password_verify, which is the safer surface.
error_log("JwtEndpoint: app '{$appIdentifier}' references user_model '{$app->user_model}' but no DataModel row defines it; falling back to KyteUser.");
return [
'user_model' => KyteUser,
'username_field' => $defaultUserField,
'password_field' => $defaultPassField,
'app' => $app,
];
}

return [
'user_model' => constant($app->user_model),
'username_field' => (string)$app->username_colname,
Expand Down
Loading