Skip to content

GML-2090 Fix authentication for password-only connections to REST++ Auth#287

Merged
chengbiao-jin merged 3 commits into
masterfrom
release_2.0.4
May 19, 2026
Merged

GML-2090 Fix authentication for password-only connections to REST++ Auth#287
chengbiao-jin merged 3 commits into
masterfrom
release_2.0.4

Conversation

@chengbiao-jin
Copy link
Copy Markdown
Collaborator

@chengbiao-jin chengbiao-jin commented May 19, 2026

User description

…instances

  • Password-only connections automatically mint a token and retry when the server signals that a token is required.
  • getToken() correctly stores the token string on the connection; every subsequent request now authenticates as expected.
  • refreshToken() correctly applies the refreshed token to the connection.
  • Token mint requests prefer the modern endpoint, falling back to the legacy one only on failure.

PR Type

Bug fix, Documentation


Description

  • Fix password-only REST++ authentication

  • Retry requests on token-required errors

  • Persist minted and refreshed tokens

  • Document 2.0.4 authentication fixes


Diagram Walkthrough

flowchart LR
  A["Password-only request"] -->|"server requires token"| B["`_req` detects `401` or `REST-10016`"]
  B -->|"mint token"| C["`getToken()` updates connection auth"]
  C -->|"retry once"| D["Original request succeeds"]
  E["Token operations"] -->|"prefer modern endpoint"| F["`POST /gsql/v1/tokens`"]
  F -->|"fallback on failure"| G["Legacy `POST /restpp/requesttoken`"]
Loading

File Walkthrough

Relevant files
Bug fix
pyTigerGraphAuth.py
Fix sync token minting and connection state                           

pyTigerGraph/pyTigerGraphAuth.py

  • Prefer the TigerGraph 4.x token endpoint first
  • Fall back to legacy token endpoint on failure
  • Store only the token string in apiToken
  • Refresh auth headers after getToken() and refreshToken()
+14/-9   
pyTigerGraphBase.py
Add sync auto-token retry handling                                             

pyTigerGraph/pyTigerGraphBase.py

  • Retry once when responses indicate token is required
  • Detect both 401 and REST-10016 retry triggers
  • Reuse request-level token minting instead of ad hoc version recovery
  • Remove redundant auth header refresh after token generation
+23/-12 
pyTigerGraphAuth.py
Fix async token persistence and headers                                   

pyTigerGraph/pytgasync/pyTigerGraphAuth.py

  • Store the parsed token string in apiToken
  • Update authHeader after token mint and refresh
  • Refresh derived auth headers after auth changes
  • Align async refresh parsing with credential-aware response handling
+6/-2     
pyTigerGraphBase.py
Add async automatic token retry                                                   

pyTigerGraph/pytgasync/pyTigerGraphBase.py

  • Add async retry-on-token-required request handling
  • Detect 401 and REST-10016 before retrying
  • Mint a token once under the async refresh lock
  • Simplify version checks by relying on generic request retry
+17/-12 
Documentation
CHANGELOG.md
Document 2.0.4 authentication bug fixes                                   

CHANGELOG.md

  • Add 2.0.4 release notes
  • Document password-only REST++ authentication fix
  • Document corrected getToken() and refreshToken() behavior
  • Note modern-first token endpoint selection
+11/-0   

…instances

- Password-only connections automatically mint a token and retry when
  the server signals that a token is required.
- getToken() correctly stores the token string on the connection; every
  subsequent request now authenticates as expected.
- refreshToken() correctly applies the refreshed token to the
  connection.
- Token mint requests prefer the modern endpoint, falling back to the
  legacy one only on failure.
@tg-pr-agent
Copy link
Copy Markdown

tg-pr-agent Bot commented May 19, 2026

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Broad Except

The new endpoint fallback catches every exception before trying the legacy token endpoint. This can mask non-endpoint failures such as timeouts, connection issues, or malformed requests and incorrectly retry against a different endpoint, making authentication failures harder to diagnose and potentially changing behavior in unexpected ways.

try:
    res = self._req(method, url, authMode=authMode,
                    data=data, resKey=None, jsonData=True)
    mainVer = 4
except:
    try:
        res = self._req(
                method, alt_url, authMode=authMode, data=alt_data, resKey=None)
Retry Scope

The automatic token mint/retry path now retries on any response body carrying REST-10016, even when the current authentication mode may not be password-based or when a caller intentionally supplied its own token. This broader retry behavior should be validated to ensure it does not silently replace caller-managed authentication state.

needs_token_retry = False
if not getattr(self, "_refreshing_token", False):
    if res.status_code == 401 and getattr(self, "_token_source", None) == "generated":
        needs_token_retry = True
    elif res.content:
        try:
            _body = json.loads(res.content)
        except (json.decoder.JSONDecodeError, ValueError):
            _body = None
        if isinstance(_body, dict) and _body.get("error") and _body.get("code") == "REST-10016":
            needs_token_retry = True
if needs_token_retry:
    with self._token_refresh_lock:
        if not getattr(self, "_refreshing_token", False):
            try:
                self._refreshing_token = True
                self.getToken()
            finally:
Version Compare

The version check still compares split version components as strings and only treats versions greater than 4.0 as unsupported. This can misclassify versions with multi-digit components and may not match the stated intent around 4.x behavior, so the boundary logic should be revalidated.

# The generic _req-level retry handles REST-10016 (mint a token, retry once),
# so no ad-hoc recovery is needed here.
version = self.getVer().split('.')
result = version[0] >= "4" and version[1] > "0"
self._cached_version_greater_than_4_0 = result

Comment thread pyTigerGraph/pyTigerGraphBase.py Outdated
Comment thread pyTigerGraph/pytgasync/pyTigerGraphBase.py Outdated
Comment thread pyTigerGraph/pyTigerGraphAuth.py
- Auto-mint a token on auth failure only when the connection's
  credentials are library-managed; surface the error when the user
  supplied an explicit token, instead of silently replacing it.
- Detect auth failure from both REST++ (REST-10016) and GSQL
  ("Authentication failed.") response bodies, in addition to HTTP 401.
- Fall back from the modern token endpoint to the legacy one only when
  the modern endpoint is genuinely absent (HTTP 404 or REST-1000
  "Endpoint is not found"); preserve the original error otherwise.
@chengbiao-jin chengbiao-jin merged commit 24c8300 into master May 19, 2026
@chengbiao-jin chengbiao-jin deleted the release_2.0.4 branch May 19, 2026 03:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant