Reputation: 317
I am trying to implement google authentication for my website, it is React front end and Spring Boot REST back end.
For my React app I've found a library that provides a Google Login button, in which I can specify 'client-id' of my app, registered in Google developer's console and the rest (redirection of the user to google authentication page, retrieval of access token/id token) is done by this library.
Now I want to send this access token to my back-end, use it to make a request to google, to verify that this front-end user is a real google user, who correctly authenticated and get this user's data by showing this access token to google (i only want email/name/sub, which is users unique Google id). Am I looking for some library to exchange this google access token for user data ?
I'm also confused by the fact that all the oauth tutorials say that when user authenticates on google page, my app would receive an Authorization Code but my front end receives, as I said, acces token and id token. Is it because of the library I'm using ? https://www.npmjs.com/package/react-google-login this is the library
This is the data that comes to my client app when user autheneticates on google page console.log(response) in browser
Thanks
Upvotes: 1
Views: 2408
Reputation: 121
Maybe I am late, but let me leave it here:
This could be a possible controller method to exchange the code for a token.
@PostMapping("/check/code/google")
public ResponseEntity<Striing> handleGoogleAuthCode(@RequestBody Map<String, String> codeMap) {
String code = codeMap.get("code");
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
Map<String, String> params = new HashMap<>();
params.put("code", code);
params.put("client_id", clientId);
params.put("client_secret", clientSecret);
String redirectUri = "https://bpnckmnjnpoohfnodnhjpehocneckmmc.chromiumapp.org/";
params.put("redirect_uri", redirectUri);
params.put("grant_type", "authorization_code");
HttpEntity<Map<String, String>> request = new HttpEntity<>(params, headers);
ResponseEntity<Map> response = restTemplate.postForEntity("https://oauth2.googleapis.com/token", request, Map.class);
Map<String, Object> responseBody = response.getBody();
String accessToken = (String) responseBody.get("access_token");
String email = profile.getEmailAddresses().get(0).getValue();
String name = profile.getNames().get(0).getGivenName();
try {
// Create an Authentication Object
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER"); // "ROLE_" is a convention
Authentication auth = new UsernamePasswordAuthenticationToken(email, null, Collections.singletonList(authority));
// Set the Authentication Object in Security Context
SecurityContextHolder.getContext().setAuthentication(auth);
} catch (Exception e) {
// Token is invalid
SecurityContextHolder.clearContext();
}
JwtUtil bean = applicationContext.getBean(JwtUtil.class);
String jwt = bean.generateSessionToken(email);
return jwt;
}
Upvotes: 1
Reputation: 31
I had the same problem as you have. I solved it by using google's GoogleIdTokenVerifier. It was very simple to set up.
This is my code:
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Collections;
@RestController
@RequestMapping(value = "/api/authenticate")
public final class AuthenticationController {
@GetMapping
public String exchange(@Autowired NetHttpTransport transport, @Autowired GsonFactory factory, HttpServletRequest request) throws GeneralSecurityException, IOException, IllegalAccessException {
// get id_token from Authorization Bearer
String token = this.getTokenFromRequest(request);
// Create verifier
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, factory)
.setAudience(Collections.singletonList(<CLIENT_ID_HERE>))
.build();
// Verify it
GoogleIdToken idToken = verifier.verify(token);
if (idToken == null) {
throw new IllegalAccessException("Invalid id_token");
}
// Access payload
System.out.println("Email: " + idToken.getPayload().getEmail());
}
public String getTokenFromRequest(HttpServletRequest request) throws IllegalAccessException {
String token = request.getHeader("Authorization");
String[] parts = token.split(" ");
if (parts.length != 2 || !parts[0].contains("Bearer")) {
throw new IllegalAccessException("Authorization Bearer format invalid. <Bearer {token}>");
}
return parts[1];
}
}
Maven dependencies:
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>1.30.4</version>
</dependency>
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client-gson</artifactId>
<version>1.21.0</version>
</dependency>
Upvotes: 3