I'm trying to create a custom authentication method for Google cloud endpoints. The idea being I can configure my ESPv2 container (an Extensible service proxy based on Envoy), which is hosted on Google cloud run, to obtain JWT's from a custom issuer, also hosted on cloud run.
Following the guide Endpoints guide for gRPC, I figure the jwks_uri:
part of the yaml file should point to a URL which exposes the public key (which I figure you can do by putting a JWK into a json file and hosting said JSON file on google cloud storage, exposing it to the public internet).
The part that has me stumped is the issuer, I've gone through RFC7519, which states that the issuer is a string or URI value. I'm not very familiar with the specific implementation of Envoy that the ESPv2 container uses, but my best guess is the issuer:
option in the yaml file is simply used to match against the domain or string that was issued from the server when the token was created.
I'm probably wrong so I'd really appreciate some guidance on this one.
Kind regards,
Despicable B
After working with the Google Cloud endpoints team, and some of the contributors for ESPv2, we figured it out (as well as found a few things to point out to anyone wanting to do this in future).
Indeed as Wayne Zhang pointed out, the issuer can be ANY string value so long as it matches the "iss" claim in the JWT payload.
e.g.
authentication:
providers:
- id: some-fancy-id
issuer: fart # <-- Don't wrapping ANY these in double-quotes
jwks_uri: https://storage.googleapis.com/your-public-bucket/jwk-public-key.json
audiences: some-specific-name
and then in your (decoded) JWT
// Header
{
"alg": "RS256",
"kid": "custom-id-system-you-specify",
"typ": "JWT"
}
// Payload
{
"aud": [
"some-specific-name"
],
"exp": 1590139950, <-- MUST be INTEGER value
"iat": 1590136350, <-- ^^
"iss": "fart",
"sub": "Here is some sulphur dioxide"
}
As you can already see from the above decoded JWT, the "exp" and "iat" claims MUST be integer values (this can be seen clearly in the RFC7519 section 4.1.4 and 4.1.6).
This seems like a simple mistake, but as the ESPv2 contributors and I found, the error messages weren't particularly helpful at helping the developer figure out what the problem was.
For example, if you had written the "iat" and "exp" claims as strings rather than integers, the ESPv2 container would inform the dev that his JWT was either not proper Base64URL formatted or was invalid JSON. Which, to the unaware, might seem like you've used the library incorrectly.
Some changes to the error messages were made to address this in future, you can see the issue that was raised, and its conclusion here.
Before claiming victory over this battle of attrition, I ran into one more error which was just about as vague as the previous.
When trying to call a method that required authentication, I was greeted with the following
grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with:
status = StatusCode.UNAUTHENTICATED
details = "Jwks remote fetch is failed"
debug_error_string = "{"created":"@1590054504.221608572","description":"Error received from peer ipv4:216.239.36.53:443","file":"src/core/lib/surface/call.cc","file_line":1056,"grpc_message":"Jwks remote fetch is failed","grpc_status":16}"
>
Which you might think means that the ESPv2 couldn't retrieve your key. The cause was three related issues.
ESPv2 only supports X509 and RSA key pairs, so don't make the same mistake I did and use EC generated key pairs.
jwcrypto does NOT add the "alg" and "kid" claims to your key file by default, make sure these are added or jwcrypto won't know what algorithm to use when signing any JWTs you've generated.
The final error was the format of the JSON file. When you call the methods to export the keys, you get the following:
{
"e":"XXXX",
"kty":"RSA",
"n":"crazyRandomNumbersAndLetters",
"alg": "RS256", <-- NOT ADDED BY DEFAULT
"kid": "custom-id-system-you-specify" <-- ^^
}
Simply providing a URL to this in a JSON file is incorrect. The proper format is as follows:
{
"keys": [
{
"e":"XXXX",
"kty":"RSA",
"n":"crazyRandomNumbersAndLetters",
"alg": "RS256", <-- NOT ADDED BY DEFAULT
"kid": "custom-id-system-you-specify" <-- ^^
}
]
}
If you do all this, it should be smooth sailing.
I apologise for getting a little off topic, but I hope others don't have to jump through as many hoops as I did to get this going :)
I can't thank the developers at ESPv2 enough for their quick replies and insight into the problem. Top job!
Best of luck coding!