Search code examples
javagoogle-app-enginefirebase-authenticationgoogle-cloud-endpointsgoogle-authentication

Authenticating users (using both Firebase and Google authentication) on Cloud Endpoints and API Explorer


Using Cloud Endpoints Frameworks for App Engine I've added authenticating with Firebase Auth in addition to authenticating with Google Accounts.

All is good and well, I can authorize client requests using Firebase Auth, but now I can no longer use API Explorer since that uses Google's authentication and results in a 401 "Invalid credentials" response.

I added Firebase Auth by doing:

    @Api(
            name = "test",
            version = "v1",
//        authenticators = {EspAuthenticator.class},
            issuers = {
                    @ApiIssuer(
                            name = "firebase",
                            issuer = "https://securetoken.google.com/PROJECT-ID",
                            jwksUri = "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken@system.gserviceaccount.com")
            },
            issuerAudiences = {
                    @ApiIssuerAudience(name = "firebase", audiences = "PROJECT-ID")
            },
            scopes = {Constants.EMAIL_SCOPE},
            clientIds = {Constants.WEB_CLIENT_ID, Constants.ANDROID_CLIENT_ID, Constants.IOS_CLIENT_ID, Constants.API_EXPLORER},
            audiences = {Constants.ANDROID_AUDIENCE},
            namespace = @ApiNamespace(ownerDomain = "XXX", ownerName = "XXX", packagePath="")
    )

A method that works with Google authentication and API Explorer is:

@ApiMethod(
)
public User getTestUserGoogle(User user) throws UnauthorizedException {
    if (user == null) {
        throw new UnauthorizedException("Invalid credentials");
    }

    return user;
}

And a method that works with Firebase Auth but not OAuth 2.0 on API Explorer is:

@ApiMethod(
        authenticators = {EspAuthenticator.class}
)
public User getTestUserFirebase(User user) throws UnauthorizedException {
    if (user == null) {
        throw new UnauthorizedException("Invalid credentials");
    }

    return user;
}

This code snippet seems to suggest EspAuthenticator.class shoud work with Google authentication: https://github.com/GoogleCloudPlatform/java-docs-samples/blob/master/appengine/endpoints-frameworks-v2/backend/src/main/java/com/example/echo/Echo.java#L128

However the API Explorer request fails with a 401 "Invalid credentials" response whenever EspAuthenticator.class is set as the authenticator.

Is there any way I can get both Google and Firebase authentication to work on the same method? The only difference between those 2 methods is EspAuthenticator.class and based on the official code snippet in the link above it looks like Google authentication should still work with the EspAuthenticator.class authenticator.


Update: The error I get from Stackdriver is:

com.google.api.server.spi.auth.EspAuthenticator authenticate: Authentication failed: com.google.common.util.concurrent.UncheckedExecutionException: com.google.api.auth.UnauthenticatedException: org.jose4j.jwt.consumer.InvalidJwtException: Unable to process JOSE object (cause: org.jose4j.lang.JoseException: Invalid JOSE Compact Serialization. Expecting either 3 or 5 parts for JWS or JWE respectively but was 2.): ya29.GmAkBDwfsFuyOCL7kqSSLelSHpOb9LJLyewtPfpeH1a4t12i8MWmzHBNliMeR9dAtOSARG2o-QlZEHisfEPYbA-Wb-Eh36zugIufmVbDe4E2TP9StAOjub8nsrhAzuGbolE (EspAuthenticator.java:86)

Also filed an issue here: https://github.com/GoogleCloudPlatform/java-docs-samples/issues/590


Solution

  • You should either add GoogleOAuth2Authenticator or EndpointsAuthenticator

    EndpointsAuthenticator is a wrapper for GoogleJwtAuthenticator, GoogleAppEngineAuthenticator, GoogleOAuth2Authenticator.

    well, your authenticators parameter is supposed to look like

    authenticators = {EspAuthenticator.class, GoogleOAuth2Authenticator.class},