Class: Attio::OAuth::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/attio/oauth/client.rb

Overview

OAuth client for handling the OAuth 2.0 authorization flow

Constant Summary collapse

OAUTH_BASE_URL =

OAuth endpoints

"https://app.attio.com/authorize"
TOKEN_URL =

Token exchange endpoint

"https://app.attio.com/oauth/token"
DEFAULT_SCOPES =

Default OAuth scopes requested if none specified

%w[
  record:read
  record:write
  object:read
  object:write
  list:read
  list:write
  webhook:read
  webhook:write
  user:read
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(client_id:, client_secret:, redirect_uri:) ⇒ Client

Returns a new instance of Client.



31
32
33
34
35
36
# File 'lib/attio/oauth/client.rb', line 31

def initialize(client_id:, client_secret:, redirect_uri:)
  @client_id = client_id
  @client_secret = client_secret
  @redirect_uri = redirect_uri
  validate_config!
end

Instance Attribute Details

#client_idObject (readonly)

Returns the value of attribute client_id.



29
30
31
# File 'lib/attio/oauth/client.rb', line 29

def client_id
  @client_id
end

#client_secretObject (readonly)

Returns the value of attribute client_secret.



29
30
31
# File 'lib/attio/oauth/client.rb', line 29

def client_secret
  @client_secret
end

#redirect_uriObject (readonly)

Returns the value of attribute redirect_uri.



29
30
31
# File 'lib/attio/oauth/client.rb', line 29

def redirect_uri
  @redirect_uri
end

Instance Method Details

#authorization_url(scopes: DEFAULT_SCOPES, state: nil, extras: {}) ⇒ Object

Generate authorization URL for OAuth flow



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/attio/oauth/client.rb', line 39

def authorization_url(scopes: DEFAULT_SCOPES, state: nil, extras: {})
  state ||= generate_state
  scopes = validate_scopes(scopes)

  params = {
    client_id: client_id,
    redirect_uri: redirect_uri,
    response_type: "code",
    scope: scopes.join(" "),
    state: state
  }.merge(extras)

  uri = URI.parse(OAUTH_BASE_URL)
  uri.query = URI.encode_www_form(params)

  {
    url: uri.to_s,
    state: state
  }
end

#exchange_code_for_token(code:, state: nil) ⇒ Object

Exchange authorization code for access token

Raises:

  • (ArgumentError)


61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/attio/oauth/client.rb', line 61

def exchange_code_for_token(code:, state: nil)
  raise ArgumentError, "Authorization code is required" if code.nil? || code.empty?

  params = {
    grant_type: "authorization_code",
    code: code,
    redirect_uri: redirect_uri,
    client_id: client_id,
    client_secret: client_secret
  }

  response = make_token_request(params)
  Token.new(response.merge(client: self))
end

#introspect_token(token) ⇒ Object

Validate token with introspection endpoint



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/attio/oauth/client.rb', line 116

def introspect_token(token)
  token_value = token.is_a?(Token) ? token.access_token : token

  params = {
    token: token_value,
    client_id: client_id,
    client_secret: client_secret
  }

  # Use Faraday directly for OAuth endpoints
  conn = create_oauth_connection
  response = conn.post("/oauth/introspect") do |req|
    req.headers["Content-Type"] = "application/x-www-form-urlencoded"
    req.body = URI.encode_www_form(params)
  end

  if response.success?
    response.body
  else
    handle_oauth_error(response)
  end
end

#refresh_token(refresh_token) ⇒ Object

Refresh an existing access token

Raises:

  • (ArgumentError)


77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/attio/oauth/client.rb', line 77

def refresh_token(refresh_token)
  raise ArgumentError, "Refresh token is required" if refresh_token.nil? || refresh_token.empty?

  params = {
    grant_type: "refresh_token",
    refresh_token: refresh_token,
    client_id: client_id,
    client_secret: client_secret
  }

  response = make_token_request(params)
  Token.new(response.merge(client: self))
end

#revoke_token(token) ⇒ Object

Revoke a token



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/attio/oauth/client.rb', line 92

def revoke_token(token)
  token_value = token.is_a?(Token) ? token.access_token : token

  params = {
    token: token_value,
    client_id: client_id,
    client_secret: client_secret
  }

  # Use Faraday directly for OAuth endpoints
  conn = create_oauth_connection
  response = conn.post("/oauth/revoke") do |req|
    req.headers["Content-Type"] = "application/x-www-form-urlencoded"
    req.body = URI.encode_www_form(params)
  end

  response.success?
rescue => e
  # Log the error if debug mode is enabled
  warn "OAuth token revocation failed: #{e.message}" if Attio.configuration.debug
  false
end