Class: Ask::MCP::Auth::OAuth

Inherits:
Object
  • Object
show all
Defined in:
lib/ask/mcp/auth/oauth.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(client_id:, client_secret: nil, token_url: nil, auth_url: nil, redirect_uri: nil, scopes: [], issuer: nil, discovery_url: nil) ⇒ OAuth

Returns a new instance of OAuth.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/ask/mcp/auth/oauth.rb', line 9

def initialize(client_id:, client_secret: nil, token_url: nil, auth_url: nil,
               redirect_uri: nil, scopes: [], issuer: nil, discovery_url: nil)
  @client_id = client_id
  @client_secret = client_secret
  @token_url = token_url
  @auth_url = auth_url
  @redirect_uri = redirect_uri
  @scopes = scopes
  @issuer = issuer
  @discovery_url = discovery_url
  @access_token = nil
  @refresh_token = nil
  @expires_at = nil
end

Instance Attribute Details

#auth_urlObject (readonly)

Returns the value of attribute auth_url.



7
8
9
# File 'lib/ask/mcp/auth/oauth.rb', line 7

def auth_url
  @auth_url
end

#client_idObject (readonly)

Returns the value of attribute client_id.



7
8
9
# File 'lib/ask/mcp/auth/oauth.rb', line 7

def client_id
  @client_id
end

#client_secretObject (readonly)

Returns the value of attribute client_secret.



7
8
9
# File 'lib/ask/mcp/auth/oauth.rb', line 7

def client_secret
  @client_secret
end

#issuerObject (readonly)

Returns the value of attribute issuer.



7
8
9
# File 'lib/ask/mcp/auth/oauth.rb', line 7

def issuer
  @issuer
end

#token_urlObject (readonly)

Returns the value of attribute token_url.



7
8
9
# File 'lib/ask/mcp/auth/oauth.rb', line 7

def token_url
  @token_url
end

Instance Method Details

#apply(headers = {}) ⇒ Object



28
29
30
# File 'lib/ask/mcp/auth/oauth.rb', line 28

def apply(headers = {})
  headers.merge("Authorization" => "Bearer #{@access_token}")
end

#authenticate!Object



32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/ask/mcp/auth/oauth.rb', line 32

def authenticate!
  if @client_secret && @token_url
    authenticate_client_credentials
  elsif @auth_url
    authenticate_authorization_code
  elsif @issuer || @discovery_url
    raise AuthError, "Call #discover! before #authenticate! to resolve endpoints"
  else
    raise AuthError, "No authentication method available"
  end
  self
end

#authenticated?Boolean

Returns:

  • (Boolean)


24
25
26
# File 'lib/ask/mcp/auth/oauth.rb', line 24

def authenticated?
  !@access_token.nil? && !expired?
end

#discover!(discovery_url: nil) ⇒ Object

Discover authorization server endpoints via OpenID Connect Discovery 1.0 (2025-11-25, SEP-797). Fetches the document at discovery_url (or the well-known URL derived from issuer per RFC 8414) and populates token_url, auth_url, and issuer. Returns self.

Raises:



65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/ask/mcp/auth/oauth.rb', line 65

def discover!(discovery_url: nil)
  require "httpx"

  url = discovery_url || @discovery_url || well_known_discovery_url
  data = fetch_json(HTTPX, url)

  @issuer = data[:issuer] if data[:issuer]
  @token_url = data[:token_endpoint] if data[:token_endpoint]
  @auth_url = data[:authorization_endpoint] if data[:authorization_endpoint]

  raise AuthError, "Discovery document has no token_endpoint" unless @token_url
  self
end

#refresh!Object

Raises:



45
46
47
48
49
# File 'lib/ask/mcp/auth/oauth.rb', line 45

def refresh!
  raise AuthError, "No refresh token available" unless @refresh_token
  perform_token_refresh
  self
end

#validate_iss!(iss) ⇒ Object

Validate an iss parameter from an authorization response (RFC 9207, 2026-07-28): when an issuer is recorded (via discovery or configuration), a present iss MUST match it. Call before redeeming an authorization code.

Raises:



55
56
57
58
59
# File 'lib/ask/mcp/auth/oauth.rb', line 55

def validate_iss!(iss)
  return self if @issuer.nil?
  raise AuthError, "iss mismatch: expected #{@issuer}, got #{iss.inspect}" unless iss.to_s == @issuer.to_s
  self
end