{"record":{"id":"db5a3f4b782d2f7a","repo":"spring-projects/spring-security","slug":"authentication-getcredentials-cannot-be-null","errorCode":null,"errorMessage":"Authentication.getCredentials() cannot be null","messagePattern":"Authentication\\.getCredentials\\(\\) cannot be null","errorType":"exception","errorClass":"BadCredentialsException","httpStatus":null,"severity":"error","filePath":"cas/src/main/java/org/springframework/security/cas/authentication/CasAuthenticationProvider.java","lineNumber":145,"sourceCode":"\t\t\t// Try to obtain from cache\n\t\t\tresult = this.statelessTicketCache.getByTicketId(authentication.getCredentials().toString());\n\t\t}\n\t\tif (result == null) {\n\t\t\tresult = this.authenticateNow(authentication);\n\t\t\tresult.setDetails(authentication.getDetails());\n\t\t}\n\t\tif (stateless) {\n\t\t\t// Add to cache\n\t\t\tthis.statelessTicketCache.putTicketInCache(result);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate CasAuthenticationToken authenticateNow(final Authentication authentication) throws AuthenticationException {\n\t\ttry {\n\t\t\tObject credentials = authentication.getCredentials();\n\t\t\tif (credentials == null) {\n\t\t\t\tthrow new BadCredentialsException(\"Authentication.getCredentials() cannot be null\");\n\t\t\t}\n\t\t\tAssertion assertion = this.ticketValidator.validate(credentials.toString(), getServiceUrl(authentication));\n\t\t\tUserDetails userDetails = loadUserByAssertion(assertion);\n\t\t\tthis.userDetailsChecker.check(userDetails);\n\t\t\tCollection<GrantedAuthority> authorities = new ArrayList<>(\n\t\t\t\t\tthis.authoritiesMapper.mapAuthorities(userDetails.getAuthorities()));\n\t\t\tauthorities.add(FactorGrantedAuthority.fromAuthority(AUTHORITY));\n\t\t\treturn new CasAuthenticationToken(this.key, userDetails, credentials, authorities, userDetails, assertion);\n\t\t}\n\t\tcatch (TicketValidationException ex) {\n\t\t\tthrow new BadCredentialsException(ex.getMessage(), ex);\n\t\t}\n\t}\n\n\t/**\n\t * Gets the serviceUrl. If the {@link Authentication#getDetails()} is an instance of\n\t * {@link ServiceAuthenticationDetails}, then\n\t * {@link ServiceAuthenticationDetails#getServiceUrl()} is used. Otherwise, the","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/cas/src/main/java/org/springframework/security/cas/authentication/CasAuthenticationProvider.java#L127-L163","documentation":"authenticateNow is the internal step that validates the service ticket against the CAS server. As a defensive invariant it re-checks that authentication.getCredentials() is non-null before calling TicketValidator.validate, throwing BadCredentialsException otherwise. (In practice the public authenticate() path already rejects empty credentials; this guards direct/internal invocation paths.)","triggerScenarios":"authenticateNow invoked via authenticate() with a token whose credentials became null between the empty-string check and validation, or by subclass/legacy call paths that bypass the earlier check — e.g. a custom Authentication whose getCredentials() returns null.","commonSituations":"Custom Authentication implementations that don't carry credentials; subclassing CasAuthenticationProvider and invoking authenticateNow or overriding authenticate and dropping the credential check; tokens created from Authorization headers or principal-only data with credentials intentionally null.","solutions":["Always supply the service ticket as credentials when building the Authentication passed to CasAuthenticationProvider.","If subclassing, keep the null-credential check before calling authenticateNow / TicketValidator.","For custom Authentication types, override supports()/authenticate properly and map credentials into getCredentials().","Catch BadCredentialsException and reject/restart the authentication flow with proper credentials."],"exampleFix":"// before\nclass MyToken extends AbstractAuthenticationToken {\n    public Object getCredentials() { return null; } // triggers error\n}\n// after\nclass MyToken extends AbstractAuthenticationToken {\n    private final String ticket;\n    public Object getCredentials() { return ticket; }\n}","handlingStrategy":"validation","validationCode":"if (authentication.getCredentials() == null) {\n    throw new BadCredentialsException(\"Service ticket required\");\n}","typeGuard":"boolean hasCredentials(Authentication a) { return a.getCredentials() != null; }","tryCatchPattern":"try {\n    return casAuthenticationProvider.authenticate(authentication);\n} catch (BadCredentialsException e) {\n    // credentials null: reject or re-prompt for ticket\n}","preventionTips":["Always populate credentials when building Authentication tokens for CAS","Don't override getCredentials() to return null in custom token classes","When subclassing CasAuthenticationProvider, preserve the null-credential guard"],"tags":["spring-security","cas","bad-credentials","null"],"backgroundTag":"missing-credentials","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}