IAP: Support for additional claim target_audience
Closed this issue · 3 comments
Hello,
I'm trying to authenticate with a service account with the following guide:
https://cloud.google.com/iap/docs/authentication-howto#authenticating_from_a_service_account
But when I try to fetch_access_token
, I get "Invalid ID token audience":
2.5.1 :001 > client = Google::Auth::ServiceAccountCredentials.make_creds(json_key_io: Rails.root.join('config', 'gcp_credentials.json'))
=> #<Google::Auth::ServiceAccountCredentials:0x00007fd589fdf000 @project_id="PROJECT", @authorization_uri=nil, @token_credential_uri=#<Addressable::URI:0x3feac4fef6ac URI:https://www.googleapis.com/oauth2/v4/token>, @client_id=nil, @client_secret=nil, @code=nil, @expires_at=nil, @issued_at=nil, @issuer="SA@PROJECT.iam.gserviceaccount.com", @password=nil, @principal=nil, @redirect_uri=nil, @scope=nil, @state=nil, @username=nil, @access_type=:offline, @expiry=60, @audience="https://www.googleapis.com/oauth2/v4/token", @signing_key=#<OpenSSL::PKey::RSA:0x00007fd589fdf050>, @extension_parameters={}, @additional_parameters={}, @connection_info=nil>
2.5.1 :002 > client.fetch_access_token
Traceback (most recent call last):
1: from (irb):2
Signet::AuthorizationError (Authorization failed. Server message:)
{"error":"invalid_scope","error_description":"Invalid OAuth scope or ID token audience provided."}
2.5.1 :003 >
When I set aud
to the client id, I get "Invalid JWT: Failed audience check":
2.5.1 :001 > client = Google::Auth::ServiceAccountCredentials.make_creds(json_key_io: Rails.root.join('config', 'gcp_credentials.json'))
=> #<Google::Auth::ServiceAccountCredentials:0x00007fc12b0a3018 @project_id="PROJECT", @authorization_uri=nil, @token_credential_uri=#<Addressable::URI:0x3fe095851690 URI:https://www.googleapis.com/oauth2/v4/token>, @client_id=nil, @client_secret=nil, @code=nil, @expires_at=nil, @issued_at=nil, @issuer="SA@PROJECT.iam.gserviceaccount.com", @password=nil, @principal=nil, @redirect_uri=nil, @scope=nil, @state=nil, @username=nil, @access_type=:offline, @expiry=60, @audience="https://www.googleapis.com/oauth2/v4/token", @signing_key=#<OpenSSL::PKey::RSA:0x00007fc12b0a3090>, @extension_parameters={}, @additional_parameters={}, @connection_info=nil>
2.5.1 :002 > client.audience = 'CLIENT-ID.apps.googleusercontent.com'
=> "CLIENT-ID.apps.googleusercontent.com"
2.5.1 :003 > client.fetch_access_token
Traceback (most recent call last):
1: from (irb):3
Signet::AuthorizationError (Authorization failed. Server message:)
{"error":"invalid_grant","error_description":"Invalid JWT: Failed audience check."}
With a target_audience
monkey patch to #to_jwt
, it is possible to retrieve an id_token
:
def to_jwt options = {}
options = deep_hash_normalize options
now = Time.new
skew = options[:skew] || 60
assertion = {
"iss" => issuer,
"aud" => audience,
"exp" => (now + expiry).to_i,
"iat" => (now - skew).to_i
}
assertion["scope"] = scope.join " " unless scope.nil?
assertion["prn"] = person unless person.nil?
assertion["sub"] = sub unless sub.nil?
+ assertion["target_audience"] = options[:target_audience] unless options[:target_audience].nil?
JWT.encode assertion, signing_key, signing_algorithm
end
2.5.1 :001 > client = Google::Auth::ServiceAccountCredentials.make_creds(json_key_io: Rails.root.join('config', 'gcp_credentials.json'))
=> #<Google::Auth::ServiceAccountCredentials:0x00007ffad3b992d8 @project_id="PROJECT", @authorization_uri=nil, @token_credential_uri=#<Addressable::URI:0x3ffd69dcc818 URI:https://www.googleapis.com/oauth2/v4/token>, @client_id=nil, @client_secret=nil, @code=nil, @expires_at=nil, @issued_at=nil, @issuer="SA@PROJECT.iam.gserviceaccount.com", @password=nil, @principal=nil, @redirect_uri=nil, @scope=nil, @state=nil, @username=nil, @access_type=:offline, @expiry=60, @audience="https://www.googleapis.com/oauth2/v4/token", @signing_key=#<OpenSSL::PKey::RSA:0x00007ffad3b99328>, @extension_parameters={}, @additional_parameters={}, @connection_info=nil>
2.5.1 :002 > res = client.fetch_access_token(target_audience: 'CLIENT-ID.apps.googleusercontent.com')
=> {"id_token"=>"[AN_ID_TOKEN]"}
Is it possible to pass the target_audience
options in another way? Or am I using the gem wrong?
Regards,
Stefan
Thanks for the report. Turns out, we're just now in the process of adding proper support for the target_audience
extra assertion and fetching ID tokens from the Google OAuth2 service. So this should be solved in the next few days.
Any updates?
Sorry, forgot to update this issue. Yes, there is now a target_audience
field on the client object in Signet 0.14.0. There is also an update to the googleauth
gem (version 0.12.0) that lets you pass a target_audience:
argument to most credential constructors to make them use identity tokens. We haven't yet updated the Ruby documentation and samples online; that's forthcoming.