thephpleague/oauth2-server · error · OAuthServerException
invalid_request
invalid_request
Error message
The request is missing a required parameter, is invalid, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "username" parameter
What it means
PasswordGrant::validateUser throws invalidRequest('username') when the token request body has no 'username' parameter. The password grant mandates both username and password in the POST body (application/x-www-form-urlencoded). The generic invalid_request message names the offending parameter to help the caller fix the request.
Solutions
- Send the token request as form-encoded with a username field: POST grant_type=password&username=...&password=...
- If your client sends JSON, switch to form data or configure the server to parse JSON bodies before calling the grant
- Check for typos in parameter names on the client side
- Log the parsed body server-side to confirm what the grant actually receives
Example fix
// before
await fetch('/token', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({grant_type:'password', username, password}) });
// after
await fetch('/token', { method: 'POST', headers: {'Content-Type': 'application/x-www-form-urlencoded'}, body: new URLSearchParams({grant_type:'password', username, password}) }); Defensive patterns
Strategy: validation
Validate before calling
$params = (array) $request->getParsedBody();
if (!isset($params['username']) || !is_string($params['username']) || $params['username'] === '') {
throw new \InvalidArgumentException('username required');
} Type guard
function hasUsername(array $params): bool {
return isset($params['username']) && is_string($params['username']) && $params['username'] !== '';
} Try / catch
try {
$token = $server->respondToAccessTokenRequest($request, $response);
} catch (OAuthServerException $e) {
if (str_contains($e->getMessage(), '"username"')) {
return $e->generateHttpResponse($response->withStatus(400));
}
throw $e;
} Prevention
- Send token requests as application/x-www-form-urlencoded
- Assert required fields client-side before hitting the token endpoint
- Never send JSON bodies unless the server is configured to parse them
When it happens
Trigger: POST to the token endpoint with grant_type=password but no username field; getRequestParameter('username', $request) returns null so the ?? throw triggers; validateUser is invoked from respondToAccessTokenRequest.
Common situations: Client sends JSON body while the server only parses form-encoded parameters; parameter name typo (user_name, email); frontend forgets to include username in the token request; middleware strips or rewrites the request body.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
AI-assisted analysis of thephpleague/oauth2-server@9d2f6fc0a0 (2026-09-15).
Data as JSON: /api/errors/4f24e008ba7270da.
Report an issue: GitHub.
Appendix: source
Thrown at src/Grant/PasswordGrant.php:86
// Issue and persist new refresh token if given
$refreshToken = $this->issueRefreshToken($accessToken);
if ($refreshToken !== null) {
$this->getEmitter()->emit(new RequestRefreshTokenEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request, $refreshToken));
$responseType->setRefreshToken($refreshToken);
}
return $responseType;
}
/**
* @throws OAuthServerException
*/
protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client): UserEntityInterface
{
$username = $this->getRequestParameter('username', $request)
?? throw OAuthServerException::invalidRequest('username');
$password = $this->getRequestParameter('password', $request)
?? throw OAuthServerException::invalidRequest('password');
$user = $this->userRepository->getUserEntityByUserCredentials(
$username,
$password,
$this->getIdentifier(),
$client
);
if ($user instanceof UserEntityInterface === false) {
$this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request));
throw OAuthServerException::invalidCredentials();
}
return $user;View on GitHub (pinned to 9d2f6fc0a0)