How I Implemented an Admin Panel with Google OAuth2 in Spring Boot (Surprisingly Simple)
Authentication is no joke. And I don't mean this in the sense that it's hard to implement—although it can be—but because it's often the key to safeguarding sensitive data. If unauthorized individuals gain access, the consequences can be significant, especially in today's world, where much of our lives exist online (for better or worse).
I was working on a personal project and wanted to implement an admin panel for managing data. To provide some context, the project is a food classification system. My country lacks a labeling or warning system for processed and ultra-processed foods, unlike countries such as Mexico to mention an example:
So, I created a system to input foods I typically consume, and it generates warnings like "high calories," "high sugar," and so on.
Back to Authentication
For authentication, I wanted a solution that was both simple to use and effective. OAuth immediately came to mind. There's nothing easier than using an account I already have on all my devices. I decided to use Google OAuth2, and to my surprise, it was incredibly easy to set up.
The first step was registering my app in the Google Cloud Console platform. While there are plenty of tutorials on this process, it's not rocket science.
I built my frontend using React, so I added a library to handle Google authentication. Within minutes, I had a token from Google ready to be used.
However, I still needed to validate it on the backend. After some research(literaly a google search), I found Google's official library for this purpose.
Setting Up Validation in Spring Boot
Since I'm using Maven for dependency management in my Spring Boot project, I added the following dependencies to my pom.xml file:
<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-oauth2-http</artifactId>
<version>1.29.0</version>
</dependency>
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>2.7.0</version>
</dependency>
Next, I followed the instructions in [Google's official documentation](https://cloud.google.com/java/docs/reference/google-api-client/latest/com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier).
Since in my app is only used for my admin endpoint I did it like this:
@PostMapping("/add")
public ResponseEntity<String> addFood(@Valid @RequestBody Food food, @RequestHeader("Authorization") String authHeader) {
GoogleIdTokenVerifier verifier = new
GoogleIdTokenVerifier.Builder(new NetHttpTransport(), new GsonFactory())
.setAudience(Collections.singletonList(clientId))
.build();
String token = authHeader.replace("Bearer ", "");
GoogleIdToken idToken;
String email;
try {
idToken = verifier.verify(token);
} catch (Exception e) {
return ResponseEntity.badRequest().body("Internal error"+ e.toString());
}
if(idToken != null){
GoogleIdToken.Payload payload = idToken.getPayload();
email = payload.getEmail();
if (email.equals(adminEmail)){
foodService.addFood(food);
return ResponseEntity.ok("Food Added");
}else{
return ResponseEntity.badRequest().body("Error");
}
}else{
return ResponseEntity.badRequest().body("idtoken is null");
}
}
How It Works
I create an instance of GoogleIdTokenVerifier and set my client ID using the setAudience method. I extract the token from the Authorization header, removing the "Bearer " prefix. Using the verifier, I validate the token by calling the verify method. If the token is not valid it will return null which is not very comfortable (I don't know why maybe for security), so if the token is valid I extract the payload and confirm that the email matches the admin's email. If everything checks out, the food is added via the foodService. Very Simple!