Class: OpenAI::Auth::WorkloadIdentityAuth

Inherits:
Object
  • Object
show all
Defined in:
lib/openai/auth/workload_identity_auth.rb,
sig/openai/auth.rbs

Constant Summary collapse

SUBJECT_TOKEN_TYPES =
{
  TokenType::JWT => "urn:ietf:params:oauth:token-type:jwt",
  TokenType::ID => "urn:ietf:params:oauth:token-type:id_token"
}.freeze
TOKEN_EXCHANGE_GRANT_TYPE =
"urn:ietf:params:oauth:grant-type:token-exchange"
DEFAULT_TOKEN_EXCHANGE_URL =
"https://auth.openai.com/oauth/token"
DEFAULT_REFRESH_BUFFER_SECONDS =
1200

Instance Method Summary collapse

Constructor Details

#initialize(config, organization_id, token_exchange_url: DEFAULT_TOKEN_EXCHANGE_URL, token_exchange: nil) ⇒ WorkloadIdentityAuth

Returns a new instance of WorkloadIdentityAuth.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/openai/auth/workload_identity_auth.rb', line 19

def initialize(
  config,
  organization_id,
  token_exchange_url: DEFAULT_TOKEN_EXCHANGE_URL,
  token_exchange: nil
)
  @config = config
  @organization_id = organization_id
  @token_exchange_url = URI(token_exchange_url)
  @token_exchange = token_exchange

  @cached_token = nil
  @cached_token_expires_at_monotonic = nil
  @cached_token_refresh_at_monotonic = nil
  @issued_token_expirations = {}
  @rejected_tokens = {}
  @refreshing = false
  @refresh_generation = nil
  @refresh_error = nil
  @mutex = Mutex.new
  @cond_var = ConditionVariable.new
end

Instance Method Details

#bound_to?(identity, transport:) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:



144
145
146
147
148
# File 'lib/openai/auth/workload_identity_auth.rb', line 144

def bound_to?(identity, transport:)
  @config.equal?(identity) &&
    X509Transport.exact_instance?(@token_exchange, X509TokenExchange) &&
    @token_exchange.bound_to?(identity, transport: transport)
end

#get_token(deadline: nil) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • deadline (Float, nil) (defaults to: nil)

    absolute monotonic deadline for this request

  • deadline: (Float, nil) (defaults to: nil)

Returns:

  • (String)


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/openai/auth/workload_identity_auth.rb', line 46

def get_token(deadline: nil)
  loop do
    check_deadline!(deadline)
    action = nil
    token = nil
    generation = nil
    previous_token = nil

    # Installing refresh cleanup is part of the state transition. No async
    # exception may observe @refreshing after it changes but before the ensure.
    Thread.handle_interrupt(Exception => :never) do
      @mutex.synchronize do
        if @refreshing
          if token_unusable?
            action = :wait
            generation = @refresh_generation
          else
            token = @cached_token
            action = :return
          end
        elsif token_unusable? || needs_refresh?
          previous_token = @cached_token
          @refreshing = true
          generation = {complete: false, error: nil, token: nil, expires_at: nil}
          @refresh_generation = generation
          action = :refresh
        else
          token = @cached_token
          action = :return
        end
      end

      if action == :refresh
        begin
          Thread.handle_interrupt(Exception => :immediate) do
            perform_refresh(deadline: deadline)
          end

        rescue StandardError => error
          fallback = false
          @mutex.synchronize do
            now = OpenAI::Internal::Util.monotonic_secs unless @token_exchange.nil?
            if now && proactive_refresh_fallback?(error, previous_token, deadline, now)
              remaining = @cached_token_expires_at_monotonic - now
              @cached_token_refresh_at_monotonic = now + [5.0, remaining / 2].min
              @refresh_error = error
              fallback = true
            else
              @refresh_error = error unless @token_exchange.nil?
              generation[:error] = error
            end
          end

          raise unless fallback
        ensure
          @mutex.synchronize do
            if generation[:error].nil?
              generation[:token] = @cached_token
              generation[:expires_at] = @cached_token_expires_at_monotonic
            end

            generation[:complete] = true
            @refreshing = false
            @cond_var.broadcast
          end
        end
      end
    end

    return token if action == :return
    if action == :wait
      token = wait_for_refresh(deadline, generation)
      return token unless token.nil?

      next
    end

    return current_token(deadline)
  end
end

#inspectString

Avoid exposing cached access tokens or identity configuration in diagnostics.

Returns:

  • (String)


153
154
155
# File 'lib/openai/auth/workload_identity_auth.rb', line 153

def inspect
  "#<#{self.class.name}:0x#{object_id.to_s(16)}>"
end

#invalidate_token(rejected_token = nil) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Parameters:

  • rejected_token (String, nil) (defaults to: nil)


128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/openai/auth/workload_identity_auth.rb', line 128

def invalidate_token(rejected_token = nil)
  @mutex.synchronize do
    if @token_exchange && rejected_token
      expires_at = @issued_token_expirations[rejected_token]
      @rejected_tokens[rejected_token] = expires_at unless expires_at.nil?
    end

    return nil unless rejected_token.nil? || rejected_token == @cached_token

    @cached_token = nil
    @cached_token_expires_at_monotonic = nil
    @cached_token_refresh_at_monotonic = nil
  end
end