: Enable logging on the token exchange but redact code_verifier and refresh_token before persisting. 7. Comparison with Other Accounting APIs | Feature | lexoffice | DATEV | Xero | QuickBooks | |---------|-----------|-------|------|-------------| | OAuth2 | ✅ PKCE | ✅ PKCE | ✅ PKCE | ✅ PKCE | | Refresh token rotation | ✅ (recommended) | ❌ | ✅ | ✅ | | Sandbox environment | ✅ | ✅ | ✅ | ✅ | | Scope discovery via metadata | ✅ OIDC Discovery | ❌ | ✅ | ✅ |
def _generate_pkce_pair(self): """Generate code_verifier and code_challenge (S256).""" self.code_verifier = secrets.token_urlsafe(64)[:128] code_challenge = hashlib.sha256(self.code_verifier.encode()).digest() # Base64url encode without padding code_challenge = secrets.token_urlsafe(32) # simplified; use proper base64url # For correctness, implement: import base64 code_challenge = base64.urlsafe_b64encode( hashlib.sha256(self.code_verifier.encode()).digest() ).decode().rstrip("=") return code_challenge lexoffice.login
# Exchange data = "grant_type": "authorization_code", "code": auth_code, "redirect_uri": self.redirect_uri, "client_id": self.client_id, "code_verifier": self.code_verifier resp = requests.post(self.TOKEN_URL, data=data) resp.raise_for_status() tokens = resp.json() return tokens # contains access_token, refresh_token, expires_in : Enable logging on the token exchange but