{"record":{"id":"5cb5f9b061a3adbf","repo":"spring-projects/spring-security","slug":"unauthorized-client","errorCode":"unauthorized_client","errorMessage":"OAuth 2.0 Parameter: client_id","messagePattern":"OAuth 2\\.0 Parameter: client_id","errorType":"error_code","errorClass":"OAuth2AuthorizationCodeRequestAuthenticationException","httpStatus":null,"severity":"error","filePath":"oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationValidator.java","lineNumber":108,"sourceCode":"\t\t.andThen(DEFAULT_SCOPE_VALIDATOR);\n\n\t@Override\n\tpublic void accept(OAuth2AuthorizationCodeRequestAuthenticationContext authenticationContext) {\n\t\tthis.authenticationValidator.accept(authenticationContext);\n\t}\n\n\tprivate static void validateAuthorizationGrantType(\n\t\t\tOAuth2AuthorizationCodeRequestAuthenticationContext authenticationContext) {\n\t\tOAuth2AuthorizationCodeRequestAuthenticationToken authorizationCodeRequestAuthentication = authenticationContext\n\t\t\t.getAuthentication();\n\t\tRegisteredClient registeredClient = authenticationContext.getRegisteredClient();\n\t\tif (!registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.AUTHORIZATION_CODE)) {\n\t\t\tif (LOGGER.isDebugEnabled()) {\n\t\t\t\tLOGGER.debug(LogMessage.format(\n\t\t\t\t\t\t\"Invalid request: requested grant_type is not allowed for registered client '%s'\",\n\t\t\t\t\t\tregisteredClient.getId()));\n\t\t\t}\n\t\t\tthrow createException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT, OAuth2ParameterNames.CLIENT_ID,\n\t\t\t\t\tauthorizationCodeRequestAuthentication, registeredClient);\n\t\t}\n\t}\n\n\tprivate static void validateRedirectUri(OAuth2AuthorizationCodeRequestAuthenticationContext authenticationContext) {\n\t\tOAuth2AuthorizationCodeRequestAuthenticationToken authorizationCodeRequestAuthentication = authenticationContext\n\t\t\t.getAuthentication();\n\t\tRegisteredClient registeredClient = authenticationContext.getRegisteredClient();\n\n\t\tString requestedRedirectUri = authorizationCodeRequestAuthentication.getRedirectUri();\n\n\t\tif (StringUtils.hasText(requestedRedirectUri)) {\n\t\t\t// ***** redirect_uri is available in authorization request\n\n\t\t\tUriComponents requestedRedirect = null;\n\t\t\ttry {\n\t\t\t\trequestedRedirect = UriComponentsBuilder.fromUriString(requestedRedirectUri).build();\n\t\t\t}","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationValidator.java#L90-L126","documentation":"This error is thrown during authorization request validation when the client submits grant_type=authorization_code (or omits it for the code flow) but the RegisteredClient is not registered with the authorization_code grant type. Per OAuth2 spec, authorization servers must reject authorization requests from clients not authorized to use the code flow, reporting unauthorized_client attributed to the client_id parameter.","triggerScenarios":"OAuth2AuthorizationCodeRequestAuthenticationValidator.validateAuthorizationGrantType runs during authentication of an authorization code request and registeredClient.getAuthorizationGrantTypes() does not contain AuthorizationGrantType.AUTHORIZATION_CODE.","commonSituations":"ClientRegistration/RegisteredClient configured only with client_credentials (or refresh_token) grant but the app still starts the code flow at /oauth2/authorize; a YAML/DB client definition missing authorization_code in its grant types; clients reconfigured after an upgrade (e.g. moving from implicit to code flow) without updating grant types.","solutions":["Add AuthorizationGrantType.AUTHORIZATION_CODE to the RegisteredClient's authorization grant types, e.g. RegisteredClient.withId(...).authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).","If the client should not use the code flow, stop sending it to /oauth2/authorize and use its registered grant type (e.g. client_credentials) instead.","Verify the client's stored configuration (YAML, JDBC, etc.) actually includes authorization_code and that the right client_id is being used."],"exampleFix":"// before\nRegisteredClient client = RegisteredClient.withId(UUID.randomUUID().toString())\n    .clientId(\"my-client\")\n    .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)\n    .build();\n// after\nRegisteredClient client = RegisteredClient.withId(UUID.randomUUID().toString())\n    .clientId(\"my-client\")\n    .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)\n    .redirectUri(\"https://example.com/callback\")\n    .build();","handlingStrategy":"validation","validationCode":"// verify before initiating the code flow\nif (!registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.AUTHORIZATION_CODE)) {\n    throw new IllegalStateException(\n        \"Client '\" + registeredClient.getClientId() + \"' is not registered for authorization_code grant\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    authenticate(authorizationRequest);\n} catch (OAuth2AuthorizationCodeRequestAuthenticationException e) {\n    if (\"unauthorized_client\".equals(e.getError().getErrorCode())) {\n        log.error(\"Client {} not registered for authorization_code; fix RegisteredClient config\", clientId);\n    }\n    throw e;\n}","preventionTips":["Always register authorization_code grant type for clients that use the browser code flow","Keep client definitions in one reviewed source (YAML/JDBC) and validate on startup","Add an integration test that starts the authorize endpoint for every registered client","Distinguish grant types per client; never reuse a client_credentials-only client for login"],"tags":["oauth2","authorization-server","client-config","grant-type"],"backgroundTag":"unauthorized-client-grant-type","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}