Class: PetstoreApiClient::Authentication::OAuth2
- Defined in:
- lib/petstore_api_client/authentication/oauth2.rb
Overview
OAuth2 authentication strategy for Petstore API
Implements OAuth2 Client Credentials flow for server-to-server authentication. Automatically handles token fetching, caching, and refresh on expiration.
This implementation follows the same security best practices as the ApiKey strategy:
-
HTTPS enforcement with warnings for insecure connections
-
Token masking in logs and debug output
-
Environment variable support for secure credential storage
-
Thread-safe token management
Constant Summary collapse
- DEFAULT_TOKEN_URL =
Default token URL for Petstore API
"https://petstore.swagger.io/oauth/token"- DEFAULT_SCOPE =
Default OAuth2 scope for Petstore API (supports both read and write)
"read:pets write:pets"- ENV_CLIENT_ID =
Environment variable names for OAuth2 credentials
"PETSTORE_OAUTH2_CLIENT_ID"- ENV_CLIENT_SECRET =
"PETSTORE_OAUTH2_CLIENT_SECRET"- ENV_TOKEN_URL =
"PETSTORE_OAUTH2_TOKEN_URL"- ENV_SCOPE =
"PETSTORE_OAUTH2_SCOPE"- TOKEN_REFRESH_BUFFER =
Minimum seconds before expiration to trigger token refresh If token expires in less than this time, fetch a new one
60- MIN_ID_LENGTH =
Minimum length requirements for credentials (security validation)
3- MIN_SECRET_LENGTH =
3
Instance Attribute Summary collapse
- #client_id ⇒ Object readonly
- #client_secret ⇒ Object readonly
- #scope ⇒ Object readonly
- #token_url ⇒ Object readonly
Class Method Summary collapse
-
.from_env ⇒ OAuth2
Create OAuth2 authenticator from environment variables.
Instance Method Summary collapse
-
#apply(env) ⇒ void
Apply OAuth2 authentication to Faraday request.
-
#configured? ⇒ Boolean
Check if OAuth2 credentials are configured.
-
#fetch_token! ⇒ OAuth2::AccessToken
Fetch a new access token from OAuth2 server.
-
#initialize(client_id: nil, client_secret: nil, token_url: DEFAULT_TOKEN_URL, scope: nil) ⇒ OAuth2
constructor
Initialize OAuth2 authenticator with client credentials.
-
#inspect ⇒ String
(also: #to_s)
String representation (masks client secret for security).
-
#token_expired? ⇒ Boolean
Check if current access token is expired or will expire soon.
Methods inherited from Base
Constructor Details
#initialize(client_id: nil, client_secret: nil, token_url: DEFAULT_TOKEN_URL, scope: nil) ⇒ OAuth2
Initialize OAuth2 authenticator with client credentials
rubocop:disable Lint/MissingSuper
99 100 101 102 103 104 105 106 107 108 |
# File 'lib/petstore_api_client/authentication/oauth2.rb', line 99 def initialize(client_id: nil, client_secret: nil, token_url: DEFAULT_TOKEN_URL, scope: nil) @client_id = client_id&.to_s&.strip @client_secret = client_secret&.to_s&.strip @token_url = token_url || DEFAULT_TOKEN_URL @scope = scope&.to_s&.strip @access_token = nil @token_mutex = Mutex.new # Thread-safe token access validate! if configured? end |
Instance Attribute Details
#client_id ⇒ Object (readonly)
67 68 69 |
# File 'lib/petstore_api_client/authentication/oauth2.rb', line 67 def client_id @client_id end |
#client_secret ⇒ Object (readonly)
71 72 73 |
# File 'lib/petstore_api_client/authentication/oauth2.rb', line 71 def client_secret @client_secret end |
#scope ⇒ Object (readonly)
79 80 81 |
# File 'lib/petstore_api_client/authentication/oauth2.rb', line 79 def scope @scope end |
#token_url ⇒ Object (readonly)
75 76 77 |
# File 'lib/petstore_api_client/authentication/oauth2.rb', line 75 def token_url @token_url end |
Class Method Details
.from_env ⇒ OAuth2
Create OAuth2 authenticator from environment variables
Loads credentials from:
-
PETSTORE_OAUTH2_CLIENT_ID
-
PETSTORE_OAUTH2_CLIENT_SECRET
-
PETSTORE_OAUTH2_TOKEN_URL (optional, defaults to Petstore API)
-
PETSTORE_OAUTH2_SCOPE (optional)
127 128 129 130 131 132 133 134 |
# File 'lib/petstore_api_client/authentication/oauth2.rb', line 127 def self.from_env new( client_id: ENV.fetch(ENV_CLIENT_ID, nil), client_secret: ENV.fetch(ENV_CLIENT_SECRET, nil), token_url: ENV.fetch(ENV_TOKEN_URL, DEFAULT_TOKEN_URL), scope: ENV.fetch(ENV_SCOPE, nil) ) end |
Instance Method Details
#apply(env) ⇒ void
This method returns an undefined value.
Apply OAuth2 authentication to Faraday request
Adds Authorization header with Bearer token. Automatically fetches or refreshes token if needed.
151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/petstore_api_client/authentication/oauth2.rb', line 151 def apply(env) return unless configured? # Warn if sending credentials over insecure connection warn_if_insecure!(env) # Ensure we have a valid token ensure_valid_token! # Add Authorization header with Bearer token env.request_headers["Authorization"] = "Bearer #{@access_token.token}" end |
#configured? ⇒ Boolean
Check if OAuth2 credentials are configured
175 176 177 178 |
# File 'lib/petstore_api_client/authentication/oauth2.rb', line 175 def configured? !@client_id.nil? && !@client_id.empty? && !@client_secret.nil? && !@client_secret.empty? end |
#fetch_token! ⇒ OAuth2::AccessToken
Fetch a new access token from OAuth2 server
Uses Client Credentials flow to obtain an access token. Token is cached and reused until expiration.
194 195 196 197 198 199 200 201 202 |
# File 'lib/petstore_api_client/authentication/oauth2.rb', line 194 def fetch_token! @token_mutex.synchronize do client = build_oauth2_client @access_token = client.client_credentials.get_token(scope: @scope) rescue ::OAuth2::Error => e raise AuthenticationError, "OAuth2 token fetch failed: #{e.message}" end end |
#inspect ⇒ String Also known as: to_s
String representation (masks client secret for security)
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'lib/petstore_api_client/authentication/oauth2.rb', line 234 def inspect return unconfigured_inspect unless configured? # Use base class method to mask credentials masked_secret = mask_credential(@client_secret, 3) token_status = if @access_token.nil? "no token" elsif token_expired? "token expired" else "token valid" end "#<#{self.class.name} client_id=#{@client_id} secret=#{masked_secret} (#{token_status})>" end |
#token_expired? ⇒ Boolean
Check if current access token is expired or will expire soon
Returns true if token is nil, already expired, or expires within TOKEN_REFRESH_BUFFER seconds.
216 217 218 219 220 221 222 223 224 |
# File 'lib/petstore_api_client/authentication/oauth2.rb', line 216 def token_expired? return true if @access_token.nil? return true if @access_token.expired? # Refresh if expiring soon (within buffer window) return false if @access_token.expires_at.nil? Time.now.to_i >= (@access_token.expires_at - TOKEN_REFRESH_BUFFER) end |