feat(solis): OAuth 2.0 bearer auth mode alongside HMAC api-key#4078
Open
mgazza wants to merge 2 commits into
Open
feat(solis): OAuth 2.0 bearer auth mode alongside HMAC api-key#4078mgazza wants to merge 2 commits into
mgazza wants to merge 2 commits into
Conversation
SolisAPI gains a dual-mode auth path via the shared OAuthMixin: - initialize() accepts auth_method/access_token/token_expires_at/token_hash; OAuth mode uses the OAuth host (api-oauth2.soliscloud.com) with a Bearer header - _build_headers branches Bearer (OAuth) vs HMAC-SHA1 (api-key) - _execute_request proactively refreshes the token and handles 401/403 via the oauth-refresh edge function (provider 'solis'); cid/value control payloads unchanged - components.py: api_key/api_secret now optional; adds solis_auth_method/access_token/ token_expires_at/token_hash config args - test: OAuth/HMAC header selection NOTE: OAuth read/control endpoint paths reuse the HMAC paths at the OAuth host per design #366 approach 1 — to be confirmed by the manual smoke-test gate before prod use. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…sh failure Addresses quick-review findings: - initialize() raises a clear error if api_key/api_secret are missing in api-key mode (components.py made them optional, removing the old required-field guard; without this a misconfigured instance crashed later on None.encode()) - _execute_request raises immediately if the OAuth token can't be obtained, and _with_retry aborts when oauth_failed is set — so a permanent auth failure surfaces fast instead of burning the full retry window hitting the API with a bad token Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds dual authentication support to the SolisCloud integration so it can use either the existing HMAC api_key/api_secret flow or an OAuth 2.0 Bearer token flow (via the shared OAuthMixin). The intent is to keep existing users on the current HMAC path by default while enabling an alternative OAuth mode.
Changes:
- Added OAuth-capable initialization and request handling to
SolisAPI, including Bearer header construction and token refresh / 401 handling. - Updated component wiring so Solis can be configured with either api-key credentials or OAuth-related args (auth method, token fields).
- Added a unit test to verify header selection between OAuth (Bearer) and api-key (HMAC) modes.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| apps/predbat/solis.py | Adds OAuthMixin to SolisAPI, switches base host in OAuth mode, and branches header/auth + refresh/retry behavior. |
| apps/predbat/components.py | Makes Solis api-key creds optional and introduces new Solis OAuth-related configuration args. |
| apps/predbat/tests/test_solis.py | Adds a test validating OAuth vs HMAC header construction. |
Comment on lines
+380
to
+382
| if getattr(self, "auth_method", "api_key") == "oauth": | ||
| if not await self.check_and_refresh_oauth_token(): | ||
| raise SolisAPIError("Solis OAuth token unavailable — reconnect required", status_code=401) |
Comment on lines
+396
to
+399
| "auth_method": {"required": False, "config": "solis_auth_method", "default": "api_key"}, | ||
| "access_token": {"required": False, "config": "solis_access_token"}, | ||
| "token_expires_at": {"required": False, "config": "solis_token_expires_at"}, | ||
| "token_hash": {"required": False, "config": "solis_token_hash"}, |
| print("ERROR: OAuth _build_headers should not include Content-MD5") | ||
| failed = True | ||
|
|
||
| # API-key mode (default mock has no auth_method) — HMAC 'API <key>:<sig>' |
Comment on lines
+377
to
+382
| # OAuth: proactively refresh the token before the call (no-op for api-key mode). | ||
| # If the token can't be obtained (refresh failed / needs reauth), fail fast — the | ||
| # oauth_failed flag below makes _with_retry abort instead of looping with a bad token. | ||
| if getattr(self, "auth_method", "api_key") == "oauth": | ||
| if not await self.check_and_refresh_oauth_token(): | ||
| raise SolisAPIError("Solis OAuth token unavailable — reconnect required", status_code=401) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a dual-mode auth path to the Solis driver via the shared
OAuthMixin, so SolisCloud can be driven with an OAuth 2.0 Bearer token (refreshed through the SaaSoauth-refreshedge function) as an alternative to the existing HMAC api-key. Existing api-key users are unaffected —auth_methoddefaults toapi_keyand the HMAC path is unchanged.Changes
initialize()acceptsauth_method/access_token/token_expires_at/token_hash; OAuth mode uses the OAuth host (api-oauth2.soliscloud.com) with a Bearer header._build_headersbranches Bearer (OAuth) vs HMAC-SHA1 (api-key);_execute_requestproactively refreshes and handles 401/403; cid/value control payloads unchanged.components.py:api_key/api_secretnow optional, with a startup guard that requires them in api-key mode; addssolis_auth_method/access_token/token_expires_at/token_hashargs._with_retryaborts fast when OAuth refresh has permanently failed (no retry-window hang).🤖 Generated with Claude Code