Module: DWH::Adapters::OpenAuthorizable

Included in:
Snowflake
Defined in:
lib/dwh/adapters/open_authorizable.rb

Overview

OpenAuthorizable aka OAuth module will add functionality to get and refresh access tokens for databases that supported OAuth.

To use this module include it in your adapter and call the oauth_with class method.

Examples:

Endpoint that needs to use instance to generate

oauth_with authorize: ->(adapter) { "url#{config[:val]}"}, tokenize: "http://blue.com"

Get authorization_url

adapter.authorization_url
Then capture the code and gen tokens

Generate acess tokens

adapter.generate_oauth_tokens(code_from_authorization)
# this will also apply the tokens

Reuse cached tokens

adapter.apply_oauth_tokens(access_token: 'myaccesstoken', refresh_token: 'rtoken', expires_at: Time.now)

Defined Under Namespace

Modules: ClassMethods

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



40
41
42
43
44
45
46
# File 'lib/dwh/adapters/open_authorizable.rb', line 40

def self.included(base)
  base.extend(ClassMethods)
  base.config :oauth_client_id, String, required: false, message: 'OAuth client_id'
  base.config :oauth_client_secret, String, required: false, message: 'OAuth client_secret'
  base.config :oauth_redirect_uri, String, required: false, message: 'OAuth redirect_uri'
  base.config :oauth_scope, String, required: false, message: 'OAuth redirect_url'
end

Instance Method Details

#apply_oauth_tokens(access_token:, refresh_token: nil, expires_at: nil) ⇒ Object

You can reuse existing tokens that were saved outside of this app by passing it here. This could be tokens cached from a previous call to @see #generate_oauth_tokens

param access_token [String] the access token

Parameters:

  • refresh_token (String) (defaults to: nil)

    optional refresh token



69
70
71
72
73
# File 'lib/dwh/adapters/open_authorizable.rb', line 69

def apply_oauth_tokens(access_token:, refresh_token: nil, expires_at: nil)
  @oauth_access_token = access_token
  @oauth_refresh_token = refresh_token
  @token_expires_at = expires_at
end

#authorization_url(state: SecureRandom.hex(16), scope: nil) ⇒ Object

Generate authorization URL for user to visit



49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/dwh/adapters/open_authorizable.rb', line 49

def authorization_url(state: SecureRandom.hex(16), scope: nil)
  params = {
    'response_type' => 'code',
    'client_id' => oauth_client_id,
    'redirect_uri' => oauth_redirect_uri,
    'state' => state,
    'scope' => scope || oauth_scope || oauth_settings[:default_scope]
  }.compact

  uri = URI(oauth_settings[:authorize])
  uri.query = URI.encode_www_form(params)
  uri.to_s
end

#generate_oauth_tokens(authorization_code) ⇒ Object

Takes the given authorization code and generates new access and refresh tokens. It will also apply them.

Parameters:

  • authorization_code (String)

    this code should come from the redirect that is captured from the #authorization_url



79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/dwh/adapters/open_authorizable.rb', line 79

def generate_oauth_tokens(authorization_code)
  params = {
    grant_type: 'authorization_code',
    code: authorization_code,
    redirect_uri: oauth_redirect_uri
  }

  response = oauth_http_client.post(oauth_tokenization_url) do |req|
    req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
    req.headers['Authorization'] = basic_auth_header
    req.body = URI.encode_www_form(params)
  end
  oauth_token_response(response)
end

#oauth_access_tokenString

This will return the current access_token or if it expired and refresh_token token is available it will generate a new token.

Returns:

  • (String)

    access token

Raises:



118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/dwh/adapters/open_authorizable.rb', line 118

def oauth_access_token
  if token_expired? && @oauth_refresh_token
    refresh_access_token

    # return token unless exception was raised
    @oauth_access_token
  elsif @oauth_access_token
    @oauth_access_token
  else
    raise AuthenticationError,
          'Access token was never set. Either run the auth flow or set the tokens via apply_oauth_tokens method.'
  end
end

#oauth_authenticated?Boolean

Check if we have a valid access token

Returns:



133
134
135
# File 'lib/dwh/adapters/open_authorizable.rb', line 133

def oauth_authenticated?
  @oauth_access_token && !token_expired?
end

#oauth_settingsObject



156
157
158
159
160
# File 'lib/dwh/adapters/open_authorizable.rb', line 156

def oauth_settings
  @oauth_settings ||= self.class.oauth_settings.transform_values do
    it.is_a?(Proc) ? it.call(self) : it
  end
end

#oauth_token_infoObject

Get current state of tokens



138
139
140
141
142
143
144
145
146
# File 'lib/dwh/adapters/open_authorizable.rb', line 138

def oauth_token_info
  {
    access_token: @oauth_access_token,
    refresh_token: @oauth_refresh_token,
    expires_at: @token_expires_at,
    expired: token_expired?,
    authenticated: oauth_authenticated?
  }
end

#oauth_tokenization_urlObject



162
163
164
# File 'lib/dwh/adapters/open_authorizable.rb', line 162

def oauth_tokenization_url
  oauth_settings[:tokenize]
end

#refresh_access_tokenObject

Refresh access token using refresh token



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/dwh/adapters/open_authorizable.rb', line 95

def refresh_access_token
  raise AuthenticationError, 'No refresh token available' unless @oauth_refresh_token

  params = {
    grant_type: 'refresh_token',
    refresh_token: @oauth_refresh_token
  }

  response = oauth_http_client.post(oauth_tokenization_url) do |req|
    req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
    req.headers['Authorization'] = basic_auth_header
    req.body = URI.encode_www_form(params)
  end

  oauth_token_response(response)
end

#validate_oauth_configObject

Raises:



148
149
150
151
152
153
154
# File 'lib/dwh/adapters/open_authorizable.rb', line 148

def validate_oauth_config
  raise ConfigError, 'Missing config: oauth_client_id. Required for OAuth.' unless config[:oauth_client_id]
  raise ConfigError, 'Missing config: oauth_client_secret. Required for OAuth.' unless config[:oauth_client_secret]
  raise ConfigError, 'Missing config: oauth_redirect_url. Required for OAuth.' unless config[:oauth_redirect_uri]

  oauth_settings
end