Reputation: 75
I have integrated IdentityServer4 in spring Boot project.
I want to know how to add code_verifier to call "/connect/token" of IdentityServer?
I receive code in the redirecturl as follows,
First Redirect: https://idsrv4test.com/connect/authorize?response_type=code&client_id=client_id&scope=id_number%20openid%20email%20roles%20profile&state=SDGHMnvw0UJZyylFr752jBAWS2ahGIwBiavF0YsRtoI%3D&redirect_uri=https://127.0.0.1:9443/signin-oidc&code_challenge_method=S256&nonce=_8fJthx0jlqX_2tJKSkwvs_r4RfxIjU4NokGGpSZIF0&code_challenge=<this_encrypted_text>
I construct a resttemplate in my project to call "/connect/token" as per
POST /connect/token CONTENT-TYPE application/x-www-form-urlencoded
client_id=client_id&
client_secret=secret&
grant_type=authorization_code&
code=returned_code&
redirect_uri=https://127.0.0.1:9443/signin-oidc
code_verifier=<this_encrypted_text>
In the requestBody I set code_verifier=<this_encrypted_text> But I get "invalid_grant". It means as per the spec docs https://datatracker.ietf.org/doc/html/rfc7636#page-10 code_verifier == code_challenge. is flase
For your reference SecurityConfig class is as such
@EnableWebSecurity
public class ConfigSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
PortMapperImpl portMapper = new PortMapperImpl();
portMapper.setPortMappings(Collections.singletonMap("9443","9443"));
PortResolverImpl portResolver = new PortResolverImpl();
portResolver.setPortMapper(portMapper);
LoginUrlAuthenticationEntryPoint entryPoint = new LoginUrlAuthenticationEntryPoint(
"/login");
entryPoint.setPortMapper(portMapper);
entryPoint.setPortResolver(portResolver);
http.exceptionHandling()
.authenticationEntryPoint(entryPoint)
.and()
.authorizeRequests()
.antMatchers("/login","/css/*", "/images/*","/signin-oidc","/test")
.permitAll()
.anyRequest()
.authenticated()
.and()
.oauth2Login()
.loginPage("/login")
.and()
.logout().logoutUrl("/logout")
.logoutSuccessHandler(oidcLogoutSuccessHandler());
}
@Autowired
private ClientRegistrationRepository clientRegistrationRepository;
private LogoutSuccessHandler oidcLogoutSuccessHandler() {
OidcClientInitiatedLogoutSuccessHandler oidcLogoutSuccessHandler =
new OidcClientInitiatedLogoutSuccessHandler(
this.clientRegistrationRepository);
oidcLogoutSuccessHandler.setPostLogoutRedirectUri(
URI.create("http://localhost:9443"));
return oidcLogoutSuccessHandler;
}
}
And my application.yml is as follows,
server:
port: 9443
ssl:
key-store: classpath:asif1.jks
key-store-password: xxxxx
key-store-type: pkcs12
key-store-alias: server
spring:
security:
oauth2:
client:
registration:
idsrv4:
client-name: client_name_test
client-id: client_id_test
client-secret: Marines
client-authentication-method: none
authorization-grant-type: authorization_code
redirect-uri: "https://127.0.0.1:9443/signin-oidc"
scope: "id_number,openid,email,roles,profile"
provider:
idsrv4:
authorization-uri: https://idsrv4test.com/connect/authorize
issuer-uri: https://idsrv4test.com
token-uri: https://idsrv4test.com/connect/token
user-info-uri: https://idsrv4test.com/connect/userinfo
user-name-attribute: sub
jwk-set-uri: https://idsrv4test.com/.well-known/openid-configuration/jwks
Any help ?
Upvotes: 1
Views: 737
Reputation: 75
I finally resolved this issue. But still not satisfied with the methodology. Yet, it works gracefully. What I expected from OAuth2AuthorizationRequestResolver that the request to get the jwt token gets created internally and I should be unaware of the random string generated as code_challenge(to implement PKCE).
I still request to share if somebody has a working example of authenticating and getting token by just providing required confs without me implementing and overriding OAuth2AuthorizationRequestResolver. So, here i go
To implement OAuth2AuthorizationRequestResolver please follow https://developer.okta.com/blog/2020/01/23/pkce-oauth2-spring-boot
then in method addPkceParameters
String codeVerifier = this.secureKeyGenerator.generateKey();
attributes.put(PkceParameterNames.CODE_VERIFIER, codeVerifier);
codeVerifier is the string which we need to send alongwith the request for /connect/token
Now, its all up to you how you get this randomly generated string in your controller to send the request.
I have hard coded it ;-) for time being. But this I know does not fulfill the purpose of PKCE.
Also, in your class extending WebSecurityConfigurerAdapter , configure(HttpSecurity http) method must contain "/oauth2/authorization" as base url
somethg like this
http.exceptionHandling()
.authenticationEntryPoint(entryPoint)
.and()
.authorizeRequests()
.antMatchers("/login","/css/*", "/static/**", "/images/*","/test","/signin-oidc","/logoutSession")
.permitAll()
.anyRequest()
.authenticated()
.and()
.oauth2Login()
.authorizationEndpoint()
.authorizationRequestResolver(new CustomAuthorizationRequestResolver(
clientRegistrationRepository, "/oauth2/authorization"
))
.and()
.loginPage("/login").and().logout().logoutUrl("/logout")
.logoutSuccessHandler(oidcLogoutSuccessHandler());
Upvotes: 1