firebase / firebase-admin-go

Firebase Admin Go SDK
Apache License 2.0
1.16k stars 248 forks source link

If `FIREBASE_AUTH_EMULATOR_HOST` is set, `VerifyIDToken` calls the Firebase Emulator, but shouldn't #536

Open arzonus opened 1 year ago

arzonus commented 1 year ago

[REQUIRED] Step 2: Describe your environment

[REQUIRED] Step 3: Describe the problem

I am working on functionality using AdminSDK to verify ID tokens by the VerifyIDToken function. I would like to write tests including calls of the method, but I found that the SDK tries to call a Firebase Emulator, which host is defined by FIREBASE_AUTH_EMULATOR_HOST variable.

I was surprised because I was sure VerifyIDToken shouldn't call the emulator to check user revocation. I found the place where the problem happens. Could you please describe the reason for this behavior or help me to avoid calls to the emulator?

Relevant Code:


// IDToken returns a valid ID token
func IDToken(uid string) (string, error) {
    const projectID = "project-id"

    var headers = map[string]interface{}{
        "alg": "none",
        "typ": "JWT",
    }

    jsonHeaders, err := json.Marshal(headers)
    if err != nil {
        return "", err
    }
    encodedHeaders := jwt.EncodeSegment(jsonHeaders)

    var claims = map[string]interface{}{
        "aud":       projectID,
        "iss":       "https://securetoken.google.com/" + projectID,
        "iat":       time.Now().Unix() - 100,
        "exp":       time.Now().Unix() + 3600,
        "auth_time": time.Now().Unix() - 100,
        "sub":       "1234567890",
        "uid":       uid,
    }

    jsonClaims, err := json.Marshal(claims)
    if err != nil {
        return "", err
    }
    encodedClaims := jwt.EncodeSegment(jsonClaims)

    return encodedHeaders + "." + encodedClaims + ".", nil
}

func check() {
  ctx := context.Background()
  token, _ := IDToken("uid")
  os.Setenv("FIREBASE_AUTH_EMULATOR_HOST", "localhost:9099")

  app, _ := firebase.NewApp(ctx, nil)
  auth, _ :=  app.Auth(ctx)
  t, err := auth.VerifyIDToken(ctx, token)
  if err != nil {
    fmt.Println(err)
  }
}

I get this error

failed to establish a connection: Post \"http://localhost:9099/identitytoolkit.googleapis.com/v1/projects/project-id/accounts:lookup\": dial tcp [::1]:9099: connect: connection refused"

Thank you!

lecajer commented 2 days ago

In https://pkg.go.dev/firebase.google.com/go/v4/auth#Client.VerifyIDToken

In non-emulator mode, this function does not make any RPC calls most of the time. The only time it makes an RPC call is when Google public keys need to be refreshed. These keys get cached up to 24 hours, and therefore the RPC overhead gets amortized over many invocations of this function.

This might mean that in emulator mode it is expected that it does RPC calls. I don't see a reason it should call the auth server since the JWT token contains the data.