0

I have hosted a React app in firebase. And created Google Cloud Functions and deployed directly to GCP Cloud Functions.

API Gateway is setup to do APIKey/JWT validations before calling the functions. I added the Cloud Functions Invoker role to allAuthenticatedUsers. But when I make request via curl it fails (401: Unauthorized) with below message.

Message: Your client does not have permission to the requested URL

I am using the token from user.getIdToken() and making call with below curl command

curl --request GET --header "Authorization: Bearer ${TOKEN}" $AUTH_GATEWAY_URL

I get the valid api response, if I add the Cloud Functions Invoker role to allUsers .

I referred couple of SO questions below

SO Q1: Issue was using access token, instead of IdToken.

SO Q2: In my case, the JWT issuer is matching.

I am not sure what I am missing. Any suggestions would be greatly appreciated.

2
  • I think the issue you are having is that the Identity Token does not have the correct audience aud set. This needs to be the Cloud Function URL (including the function name). Commented Mar 10, 2021 at 5:58
  • Thanks @John Hanley. I checked the JWT token it has the aud same as x-google-audiences in swagger (same as app name). iss matching to the x-google-issuer provided in the swagger. Commented Mar 10, 2021 at 6:03

1 Answer 1

1

If you deploy your Cloud Functions without the help of firebase (in this case you can take advantage of the callable function to reduce boilerplate, mentioned in SO Q2).

But it force you to use NodeJS.

When using GCP Cloud Functions it does not know which service to authenticate JWT to so we have to do it our self.

package middleware

import (
    "context"
    "net/http"
    "strings"

    "firebase.google.com/go/auth"
    "github.com/gin-gonic/gin"
)

const (
    UID       = "uid"
    UserEmail = "user-email"
)

type header struct {
    Authorization string `header:"Authorization"`
}

func ValidateFirebaseAuthToken(auth *auth.Client) gin.HandlerFunc {
    return func(c *gin.Context) {
        defer c.Next()

        var h header
        c.ShouldBindHeader(&h)
        splitToken := strings.Split(h.Authorization, "Bearer ")
        if h.Authorization == "" || len(splitToken) < 2 {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
                "error": "must provide Authorization Bearer",
            })
            return
        }
        token := splitToken[1]
        tk, err := auth.VerifyIDToken(context.Background(), token)
        if err != nil {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
                "error": "cannot verify token",
            })
            return
        }
        c.Set(UID, tk.UID)
        if email, ok := tk.Claims["email"].(string); ok {
            c.Set(UserEmail, email)
        }
    }
}

I normally use the above in my Go function. Notice the line:

        tk, err := auth.VerifyIDToken(context.Background(), token)

Which will verify the Bearer <token> with firebase auth.

So I have the Cloud Functions access to allUsers and do this firebase Authentication layer in code.

For other languages you can have a look at this link https://firebase.google.com/docs/auth/admin/verify-id-tokens#verify_id_tokens_using_the_firebase_admin_sdk

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you @Chop TRAN for looking into this. I am doing the JWT validation in APIGateway, as mentioned here cloud.google.com/endpoints/docs/openapi/… (openapi v2). Isn't the above code to validate/get claims from the token in application/function?
If you doing the JWT at the API Gateway (GCP Endpoints in this case) It will validate and the request will be forward to your service (your Cloud Functions). Here the important part is to config the Endpoints correctly in your project. And modify your code to decode the header X-Endpoint-API-UserInfo using base64 like mentioned in the document.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.