Class: Rubino::OAuth::Provider
- Inherits:
-
Object
- Object
- Rubino::OAuth::Provider
- Defined in:
- lib/rubino/oauth/provider.rb,
lib/rubino/oauth/provider/github.rb,
lib/rubino/oauth/provider/google.rb
Overview
Abstract OAuth 2.0 provider. Subclasses declare endpoints + default scopes and implement #fetch_account_info to populate account_id/account_email after a successful token exchange.
Configured per-provider with client_id, client_secret, scopes from rubino.yml. PKCE (S256) is enabled by default for the auth_code flow. The agent is stateless across the redirect: the client persists the returned state and code_verifier between connect and callback.
Defined Under Namespace
Instance Attribute Summary collapse
-
#client_id ⇒ Object
readonly
Returns the value of attribute client_id.
-
#client_secret ⇒ Object
readonly
Returns the value of attribute client_secret.
-
#metadata ⇒ Object
readonly
Returns the value of attribute metadata.
-
#scopes ⇒ Object
readonly
Returns the value of attribute scopes.
Class Method Summary collapse
- .authorize_path ⇒ Object
- .default_scopes ⇒ Object
- .display_name ⇒ Object
- .id ⇒ Object
- .site ⇒ Object
- .token_path ⇒ Object
Instance Method Summary collapse
-
#build_authorize_request(redirect_uri:, scopes: nil, extra: {}) ⇒ Hash
Build the authorize URL the client must redirect the user to.
-
#exchange_code(code:, redirect_uri:, code_verifier:) ⇒ Hash
Exchange the authorization code for tokens.
-
#fetch_account_info(_access_token) ⇒ Hash
Provider-specific call to /userinfo (or equivalent) using the access token.
- #id ⇒ Object
-
#initialize(client_id:, client_secret:, scopes: nil, metadata: {}) ⇒ Provider
constructor
A new instance of Provider.
- #refresh(refresh_token) ⇒ Object
Constructor Details
#initialize(client_id:, client_secret:, scopes: nil, metadata: {}) ⇒ Provider
Returns a new instance of Provider.
45 46 47 48 49 50 |
# File 'lib/rubino/oauth/provider.rb', line 45 def initialize(client_id:, client_secret:, scopes: nil, metadata: {}) @client_id = client_id @client_secret = client_secret @scopes = (scopes || self.class.default_scopes).map(&:to_s) @metadata = end |
Instance Attribute Details
#client_id ⇒ Object (readonly)
Returns the value of attribute client_id.
19 20 21 |
# File 'lib/rubino/oauth/provider.rb', line 19 def client_id @client_id end |
#client_secret ⇒ Object (readonly)
Returns the value of attribute client_secret.
19 20 21 |
# File 'lib/rubino/oauth/provider.rb', line 19 def client_secret @client_secret end |
#metadata ⇒ Object (readonly)
Returns the value of attribute metadata.
19 20 21 |
# File 'lib/rubino/oauth/provider.rb', line 19 def @metadata end |
#scopes ⇒ Object (readonly)
Returns the value of attribute scopes.
19 20 21 |
# File 'lib/rubino/oauth/provider.rb', line 19 def scopes @scopes end |
Class Method Details
.authorize_path ⇒ Object
33 34 35 |
# File 'lib/rubino/oauth/provider.rb', line 33 def self. raise NotImplementedError end |
.default_scopes ⇒ Object
41 42 43 |
# File 'lib/rubino/oauth/provider.rb', line 41 def self.default_scopes [] end |
.display_name ⇒ Object
25 26 27 |
# File 'lib/rubino/oauth/provider.rb', line 25 def self.display_name id.to_s.capitalize end |
.id ⇒ Object
21 22 23 |
# File 'lib/rubino/oauth/provider.rb', line 21 def self.id raise NotImplementedError end |
.site ⇒ Object
29 30 31 |
# File 'lib/rubino/oauth/provider.rb', line 29 def self.site raise NotImplementedError end |
.token_path ⇒ Object
37 38 39 |
# File 'lib/rubino/oauth/provider.rb', line 37 def self.token_path raise NotImplementedError end |
Instance Method Details
#build_authorize_request(redirect_uri:, scopes: nil, extra: {}) ⇒ Hash
Build the authorize URL the client must redirect the user to.
The returned state and code_verifier MUST be persisted by the caller and replayed on the callback — rubino keeps no per-flow session.
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/rubino/oauth/provider.rb', line 67 def (redirect_uri:, scopes: nil, extra: {}) state = SecureRandom.urlsafe_base64(32) code_verifier = SecureRandom.urlsafe_base64(64) code_challenge = pkce_challenge(code_verifier) url = oauth2_client.auth_code.( redirect_uri: redirect_uri, scope: Array(scopes || @scopes).join(scope_separator), state: state, code_challenge: code_challenge, code_challenge_method: "S256", **extra ) { authorize_url: url, state: state, code_verifier: code_verifier } end |
#exchange_code(code:, redirect_uri:, code_verifier:) ⇒ Hash
Exchange the authorization code for tokens.
92 93 94 95 96 97 98 99 |
# File 'lib/rubino/oauth/provider.rb', line 92 def exchange_code(code:, redirect_uri:, code_verifier:) token = oauth2_client.auth_code.get_token( code, redirect_uri: redirect_uri, code_verifier: code_verifier ) normalize(token) end |
#fetch_account_info(_access_token) ⇒ Hash
Provider-specific call to /userinfo (or equivalent) using the access token.
112 113 114 |
# File 'lib/rubino/oauth/provider.rb', line 112 def fetch_account_info(_access_token) raise NotImplementedError end |
#id ⇒ Object
52 53 54 |
# File 'lib/rubino/oauth/provider.rb', line 52 def id self.class.id end |
#refresh(refresh_token) ⇒ Object
101 102 103 104 |
# File 'lib/rubino/oauth/provider.rb', line 101 def refresh(refresh_token) token = OAuth2::AccessToken.new(oauth2_client, "", refresh_token: refresh_token) normalize(token.refresh!) end |