Class: Schwab::Middleware::TokenRefresh

Inherits:
Faraday::Middleware
  • Object
show all
Defined in:
lib/schwab/middleware/authentication.rb

Overview

Faraday middleware for automatic token refresh

Instance Method Summary collapse

Constructor Details

#initialize(app, options = {}) ⇒ TokenRefresh

Returns a new instance of TokenRefresh.



9
10
11
12
13
14
15
16
17
# File 'lib/schwab/middleware/authentication.rb', line 9

def initialize(app, options = {})
  super(app)
  @access_token = options[:access_token]
  @refresh_token = options[:refresh_token]
  @client_id = options[:client_id]
  @client_secret = options[:client_secret]
  @on_token_refresh = options[:on_token_refresh]
  @mutex = Mutex.new
end

Instance Method Details

#call(env) ⇒ Faraday::Response

Process the request with automatic token refresh on 401

Parameters:

  • env (Faraday::Env)

    The request environment

Returns:

  • (Faraday::Response)

    The response



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/schwab/middleware/authentication.rb', line 22

def call(env)
  # Add the current access token to the request
  env[:request_headers]["Authorization"] = "Bearer #{@access_token}"

  # Make the request
  response = @app.call(env)

  # Check if token expired (401 Unauthorized)
  if response.status == 401 && @refresh_token
    # Thread-safe token refresh
    @mutex.synchronize do
      # Double-check in case another thread already refreshed
      if response.status == 401
        refresh_access_token!

        # Retry the request with new token
        env[:request_headers]["Authorization"] = "Bearer #{@access_token}"
        response = @app.call(env)
      end
    end
  end

  response
rescue Faraday::UnauthorizedError => e
  # If we get an unauthorized error and have a refresh token, try refreshing
  if @refresh_token
    @mutex.synchronize do
      refresh_access_token!

      # Retry the request with new token
      env[:request_headers]["Authorization"] = "Bearer #{@access_token}"
      @app.call(env)
    end
  else
    raise e
  end
end