I've created a self hosted Java applicataion and I would like to use Google sign in to log in into. I followed the follwong example:
https://developers.google.com/identity/sign-in/web/
That of course work, but now I'm getting a little confuse on how I can authorize the calls on the server. In the backend I'm using Grizzly+Jersey.
As described on the Google Sig-In documentation, you can use Google API Client Library for Java in order to check the authentication token on server side.
After a user successfully signs in, get the user's ID token:
function onSignIn(googleUser) {
var idToken = googleUser.getAuthResponse().id_token;
...
}
And send the idToken
to the server in every request using the standard HTTP Authorization
header.
You can use a filter to perform authentication and/or authorization.
To bind filters to your REST endpoints, JAX-RS provides the meta-annotation @NameBinding
and can be used as following:
@NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface Secured { }
The @Secured
annotation will be used to decorate a filter class, which implements ContainerRequestFilter
, allowing you to handle the request, get and validate the token.
The ContainerRequestContext
helps you to extract information from the HTTP request.
The @Provider
annotation marks an implementation of an extension interface that should be discoverable by JAX-RS/Jersey runtime during a provider scanning phase.
@Secured
@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// Get the token header from the HTTP Authorization request header
String token =
requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
// Check if the token is present
if (token == null || token.isEmpty()) {
throw new NotAuthorizedException("Token must be provided");
}
// Validate the token
validateToken(token);
}
private void validateToken(String token) {
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier
.Builder(new NetHttpTransport(), new GsonFactory())
.setAudience(Arrays.asList(CLIENT_ID))
.build();
GoogleIdToken idToken = verifier.verify(token);
if (idToken != null) {
Payload payload = idToken.getPayload();
System.out.println("User ID: " + payload.getSubject());
} else {
throw new NotAuthorizedException("Invalid token.");
}
}
}
To bind the filter to your endpoints methods or classes, annotate them with the @Secured
annotation created above. For the methods and/or classes which are annotated, the filter will be executed.
@Path("/example")
public class MyEndpoint {
@GET
@Path("{id}")
@Produces("application/json")
public Response myUnsecuredMethod(@PathParam("id") Long id) {
// This method is not annotated with @Secured
// The security filter won't be executed before invoking this method
...
}
@DELETE
@Secured
@Path("{id}")
@Produces("application/json")
public Response mySecuredMethod(@PathParam("id") Long id) {
// This method is annotated with @Secured
// The security filter will be executed before invoking this method
...
}
}
In the example above, the security filter will be executed only for mySecuredMethod(Long)
because it's annotated with @Secured
.