class Google::Auth::OAuth2::STSClient

OAuth 2.0 Token Exchange Spec. This module defines a token exchange utility based on the [OAuth 2.0 Token Exchange](tools.ietf.org/html/rfc8693) spec. This will be mainly used to exchange external credentials for GCP access tokens in workload identity pools to access Google APIs. The implementation will support various types of client authentication as allowed in the spec.

A deviation on the spec will be for additional Google specific options that cannot be easily mapped to parameters defined in the RFC. The returned dictionary response will be based on the [rfc8693 section 2.2.1] (tools.ietf.org/html/rfc8693#section-2.2.1) spec JSON response.

Constants

URLENCODED_HEADERS

Public Class Methods

new(options = {}) click to toggle source

Create a new instance of the STSClient.

@param [String] token_exchange_endpoint

The token exchange endpoint.
# File lib/googleauth/oauth2/sts_client.rb, line 41
def initialize options = {}
  raise "Token exchange endpoint can not be nil" if options[:token_exchange_endpoint].nil?
  self.default_connection = options[:connection]
  @token_exchange_endpoint = options[:token_exchange_endpoint]
end

Public Instance Methods

exchange_token(options = {}) click to toggle source

Exchanges the provided token for another type of token based on the rfc8693 spec

@param [Faraday instance] connection A callable faraday instance used to make HTTP requests. @param [String] grant_type

The OAuth 2.0 token exchange grant type.

@param [String] subject_token

The OAuth 2.0 token exchange subject token.

@param [String] subject_token_type

The OAuth 2.0 token exchange subject token type.

@param [String] resource

The optional OAuth 2.0 token exchange resource field.

@param [String] audience

The optional OAuth 2.0 token exchange audience field.

@param [Array<String>] scopes

The optional list of scopes to use.

@param [String] requested_token_type

The optional OAuth 2.0 token exchange requested token type.

@param additional_headers (Hash<String,String>):

The optional additional headers to pass to the token exchange endpoint.

@return [Hash] A hash containing the token exchange response.

# File lib/googleauth/oauth2/sts_client.rb, line 70
def exchange_token options = {}
  missing_required_opts = [:grant_type, :subject_token, :subject_token_type] - options.keys
  unless missing_required_opts.empty?
    raise ArgumentError, "Missing required options: #{missing_required_opts.join ', '}"
  end

  # TODO: Add the ability to add authentication to the headers
  headers = URLENCODED_HEADERS.dup.merge(options[:additional_headers] || {})

  request_body = make_request options

  response = connection.post @token_exchange_endpoint, URI.encode_www_form(request_body), headers

  if response.status != 200
    raise "Token exchange failed with status #{response.status}"
  end

  MultiJson.load response.body
end

Private Instance Methods

make_request(options = {}) click to toggle source
# File lib/googleauth/oauth2/sts_client.rb, line 92
def make_request options = {}
  request_body = {
    grant_type: options[:grant_type],
    audience: options[:audience],
    scope: Array(options[:scopes])&.join(" ") || [],
    requested_token_type: options[:requested_token_type],
    subject_token: options[:subject_token],
    subject_token_type: options[:subject_token_type]
  }
  unless options[:additional_options].nil?
    request_body[:options] = CGI.escape MultiJson.dump(options[:additional_options], symbolize_name: true)
  end
  request_body
end