Class: Basecamp::OauthService
- Inherits:
-
Object
- Object
- Basecamp::OauthService
- Defined in:
- app/services/basecamp/oauth_service.rb
Overview
Handles Basecamp 4 OAuth 2.0 token exchange and refresh.
Basecamp uses standard OAuth 2.0 Authorization Code flow:
- Redirect user to authorization_url
- Basecamp redirects back with ?code=...
- Exchange code for access_token + refresh_token
- When token expires, use refresh_token to get a new pair
Reference: https://github.com/basecamp/api/blob/master/sections/authentication.md
Defined Under Namespace
Classes: TokenRefreshError
Constant Summary collapse
- AUTHORIZE_URL =
'https://launchpad.37signals.com/authorization/new'- TOKEN_URL =
'https://launchpad.37signals.com/authorization/token'- SITE_URL =
'https://launchpad.37signals.com'- PROVIDER =
'basecamp'
Instance Method Summary collapse
-
#access_token! ⇒ String
Get a valid access token, refreshing if expired.
-
#account_id ⇒ String
The configured Basecamp account ID for API calls.
-
#authorization_url(state: nil) ⇒ String
URL to redirect the user to for authorization.
-
#connected? ⇒ Boolean
Whether this CRM account has a stored Basecamp credential.
-
#disconnect! ⇒ Object
Remove the stored credential for this account (disconnect).
-
#exchange_code!(code) ⇒ OauthCredential
Exchange the authorization code for tokens and persist them.
-
#initialize(account: nil) ⇒ OauthService
constructor
A new instance of OauthService.
-
#refresh! ⇒ OauthCredential
Refresh the stored access token.
Constructor Details
#initialize(account: nil) ⇒ OauthService
Returns a new instance of OauthService.
24 25 26 27 28 29 30 |
# File 'app/services/basecamp/oauth_service.rb', line 24 def initialize(account: nil) @account = account @client_id = Heatwave::Configuration.fetch(:basecamp, :client_id) @client_secret = Heatwave::Configuration.fetch(:basecamp, :client_secret) @redirect_url = Heatwave::Configuration.fetch(:basecamp, :redirect_url) @basecamp_account_id = Heatwave::Configuration.fetch(:basecamp, :account_id) end |
Instance Method Details
#access_token! ⇒ String
Get a valid access token, refreshing if expired.
87 88 89 90 91 92 93 |
# File 'app/services/basecamp/oauth_service.rb', line 87 def access_token! credential = OauthCredential.for(PROVIDER, account: @account) raise TokenRefreshError, 'No Basecamp credential found' unless credential refresh! if credential.token_expired? credential.reload.access_token end |
#account_id ⇒ String
The configured Basecamp account ID for API calls.
97 98 99 |
# File 'app/services/basecamp/oauth_service.rb', line 97 def account_id @basecamp_account_id end |
#authorization_url(state: nil) ⇒ String
URL to redirect the user to for authorization.
Uses standard OAuth 2.0 response_type per Basecamp API docs.
36 37 38 39 40 41 42 43 44 |
# File 'app/services/basecamp/oauth_service.rb', line 36 def (state: nil) params = { response_type: 'code', client_id: @client_id, redirect_uri: @redirect_url } params[:state] = state if state.present? "#{AUTHORIZE_URL}?#{params.to_query}" end |
#connected? ⇒ Boolean
Whether this CRM account has a stored Basecamp credential.
103 104 105 |
# File 'app/services/basecamp/oauth_service.rb', line 103 def connected? OauthCredential.for(PROVIDER, account: @account).present? end |
#disconnect! ⇒ Object
Remove the stored credential for this account (disconnect).
108 109 110 |
# File 'app/services/basecamp/oauth_service.rb', line 108 def disconnect! OauthCredential.where(provider: PROVIDER, account_id: @account&.id).destroy_all end |
#exchange_code!(code) ⇒ OauthCredential
Exchange the authorization code for tokens and persist them.
49 50 51 52 53 54 55 56 57 58 59 |
# File 'app/services/basecamp/oauth_service.rb', line 49 def exchange_code!(code) response = token_request( grant_type: 'authorization_code', code: code, redirect_uri: @redirect_url, client_id: @client_id, client_secret: @client_secret ) persist_tokens!(response) end |
#refresh! ⇒ OauthCredential
Refresh the stored access token.
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'app/services/basecamp/oauth_service.rb', line 64 def refresh! credential = OauthCredential.for(PROVIDER, account: @account) raise TokenRefreshError, 'No Basecamp credential found' unless credential raise TokenRefreshError, 'No refresh token available' if credential.refresh_token.blank? response = token_request( grant_type: 'refresh_token', refresh_token: credential.refresh_token, client_id: @client_id, client_secret: @client_secret ) attrs = { access_token: response['access_token'], expires_at: response['expires_in'] ? response['expires_in'].to_i.seconds.from_now : nil } attrs[:refresh_token] = response['refresh_token'] if response['refresh_token'].present? credential.update!(attrs) credential end |