I am trying to implement authentication with google into my app, with Spring Boot as the backend framework and React.js in the frontend.
Frontend:
Basically I have a button and on an onClick event, the user will be redirected to the following link https://accounts.google.com/o/oauth2/auth?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code&scope=openid%20profile email
where the client id represents the client id given in the google console after creating a credential.
const handleGoogleLogin = async () => {
window.location.href = GOOGLE_AUTH_URL;
};
Backend:
Apart from the usual SecurityConfiguration I have created this OAuth2Configuration class where I use a builder with all the client details.
@Configuration
public class OAuth2Configuration {
@Value("${spring.security.oauth2.client.registration.google.client-id}")
private String googleClientId;
@Value("${spring.security.oauth2.client.registration.google.client-secret}")
private String googleClientSecret;
@Value("${spring.security.oauth2.client.registration.google.redirect-uri}")
private String googleRedirectUri;
@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
return new InMemoryClientRegistrationRepository(
ClientRegistration.withRegistrationId("google")
.clientId(googleClientId)
.clientSecret(googleClientSecret)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUri(googleRedirectUri)
.scope("openid", "profile", "email")
.authorizationUri("https://accounts.google.com/o/oauth2/auth")
.tokenUri("https://oauth2.googleapis.com/token")
.userInfoUri("https://openidconnect.googleapis.com/v1/userinfo")
.userNameAttributeName(IdTokenClaimNames.SUB)
.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
.clientName("Google")
.build()
);
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient() {
return new DefaultAuthorizationCodeTokenResponseClient();
}
}
From what I understand, the redirect uri’s from the backend should match the frontend.
I then make use of clientRegistrationRepository
in my OAuth2Controller where i want to get the access token from the authorization code sent after the user redirects from the consent screen but I can’t find an effective approach to do so..
@GetMapping("/oauth2/redirect")
public String getAccessToken(@RequestParam("code") String code) throws ServletException, IOException {
ClientRegistration clientRegistration = clientRegistrationRepository.findByRegistrationId("google");
String clientId = clientRegistration.getClientId();
String clientSecret = clientRegistration.getClientSecret();
String redirectUri = clientRegistration.getRedirectUri();
String tokenEndpoint = "https://oauth2.googleapis.com/token";
//...
}
Technically the code below does get the user access token from the temporary code + client details, but I imagine it can be optimized
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
String requestBody = "code=" + code +
"&client_id=" + clientId +
"&client_secret=" + clientSecret +
"&redirect_uri=" + redirectUri +
"&grant_type=authorization_code";
HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);
ResponseEntity<String> response = new RestTemplate().postForEntity(tokenEndpoint, entity, String.class);
JSONObject jsonResponse = new JSONObject(response.getBody());
String accessToken = jsonResponse.getString("access_token");
System.out.println("Access Token: " + accessToken);
System.out.println(response.getBody());