Skip to content

Shotgrid Personal Access Token based authentication for backend api endpoints#164

Open
Srijan9211 wants to merge 2 commits into
AcademySoftwareFoundation:mainfrom
Srijan9211:dna/issue55-Autodesk-PAT-based-authentication-for-backend-API-endpoints
Open

Shotgrid Personal Access Token based authentication for backend api endpoints#164
Srijan9211 wants to merge 2 commits into
AcademySoftwareFoundation:mainfrom
Srijan9211:dna/issue55-Autodesk-PAT-based-authentication-for-backend-API-endpoints

Conversation

@Srijan9211

Copy link
Copy Markdown
Collaborator

Summary

Implements ShotGrid PAT (Personal Access Token: https://aps.autodesk.com/blog/understanding-pat-its-benefits-and-how-obtain-pat) based authentication for the DNA backend API. This replaces the previous unauthenticated / Google OAuth flow with a production-ready auth system where users sign in with their ShotGrid username and Legacy Login password.

What changed:

  • Backend auth provider (shotgrid_sso.py) — new ShotGridSSOProvider that authenticates against ShotGrid's /api/v1/auth/access_token endpoint using the password grant type, issues a short-lived DNA JWT to the browser, and stores ShotGrid credentials server-side in MongoDB.
  • MongoDB session store (session_store.py) — replaces Redis with MongoDB (already used by DNA) for session storage, JWT revocation blocklist, and OAuth state tokens; TTL indexes handle automatic expiry.
  • ShotGrid connection pool (connection_pool.py) — thread-safe LRU pool of shotgun_api3 connections keyed by session ID to avoid a new TCP handshake on every API request.
  • ShotGrid auth client (shotgrid_auth_client.py) — encapsulates all interactions with ShotGrid's token endpoint (password grant, token refresh, user identity resolution).
  • Frontend login page (ShotGridLoginPage.tsx, ShotGridAuthContext.tsx) — new PAT login form (username + password), JWT auto-refresh every 25 minutes, sessionStorage for token persistence scoped to the current tab.
  • Removed — Redis dependency, Google OAuth provider, AMI/SSO callback endpoints, google-auth and redis Python packages

Auth flow:

  1. Browser POSTs username + password to POST /auth/login
  2. Backend exchanges credentials with ShotGrid → receives ShotGrid Bearer token
  3. Backend stores session (ShotGrid token + password) in MongoDB, returns a DNA JWT to the browser
  4. Every subsequent request: DNA JWT verified → session fetched from MongoDB → ShotGrid API calls run under the user's own token → ShotGrid enforces native project permissions

Cloud ShotGrid requires a Personal Access Token (PAT) bound to the user's account at profile.autodesk.com. On-prem sites work with the actual ShotGrid/LDAP password and no PAT.

Testing

  • I have tested these changes locally
  • I have run all relevant automated tests
  • I have verified this does not break existing workflows
  • For changes that can be tested in UI, I have included screenshots or gif animations of the changes.

How I Tested

Generate a PAT at Autodesk:

  1. Open your browser and go to: 1. Open your browser and go to:
  2. Sign in with your Autodesk account (the same email as your ShotGrid account)
  3. Click the Security tab in the left sidebar
  4. Find the Personal Access Tokens section → click Generate
  5. Fill in:
    • Token name: DNA Tool
    • Application scope: select Flow Production Tracking
  6. Click Generate
  7. ⚠️ Copy the token code immediately — it is shown only once. If you close this page without copying it, you must generate a new one. Paste it in Notepad temporarily.

Bind the PAT to your ASWF ShotGrid account:

  1. Open a new tab and go to: https://aswf.shotgrid.autodesk.com
  2. Log in with your Autodesk Identity if not already logged in
  3. Click your profile icon in the top-right corner → click Account Settings
  4. In the left sidebar click Legacy Login and Personal Access Token
  5. Under the Personal Access Token section:
    • Paste the token code you copied in Step 7
    • Click Bind (or Save)
  6. You should see the token name, creation date, and status — confirming it is bound

Set your Legacy Login username and password:

  1. On the same page (Legacy Login and Personal Access Token), scroll up to the Legacy Login section
  2. You will see two fields:
    • Login — this should already be pre-filled with your ShotGrid username (usually your email)
    • Password — this is blank if you have never set it
  3. Set a Legacy Login password:
    • Click Change Password or the password field
    • Enter a new password
    • ⚠️ This is NOT your Autodesk account password — it is a separate password just for API access
    • Save it somewhere safe — this is what you type into DNA's login form
  4. Click Save

Running Stack and Test:

  1. Started the stack in windows machine with
    • Backend:
      • cd dna\backend
      • docker compose -f docker-compose.yml -f docker-compose.vexa.yml -f docker-compose.local.yml -f docker-compose.local.vexa.yml build up --build
    • Frontend:
      • cd dna
      • docker build --build-arg VITE_API_BASE_URL=http://localhost:8000 --build-arg VITE_WS_URL=ws://localhost:8000/ws --build-arg VITE_AUTH_PROVIDER=shotgrid -t dna-frontend frontend/
      • docker run --name dna-frontend -p 8080:8080 -d dna-frontend
  2. Opened http://localhost:8080 — confirmed the ShotGrid PAT login form is shown (no Google button, no SSO tab)
  3. Entered a valid ShotGrid username and Legacy Login password → confirmed successful login, user name displayed in the app, projects loaded from ShotGrid
  4. Entered invalid credentials → confirmed 401 error message is shown in the login form
  5. Confirmed GET /auth/me returns { email, name, shotgrid_user_id } with a valid token
  6. Confirmed POST /auth/logout clears the session from MongoDB and the browser returns to the login page
  7. Confirmed POST /auth/refresh issues a new DNA JWT and rotates the ShotGrid token without requiring re-login
  8. Reloaded the page with a valid token in sessionStorage → confirmed the app restores the session without prompting for login again
  9. Closed and reopened the browser tab → confirmed sessionStorage is cleared and login is required (token does not persist across tab close)
  10. Restarted the backend with an active session → confirmed the app detects the dead session on next page load (401 from /auth/me) and redirects to login
image image

Implement production-ready ShotGrid PAT (username + Legacy Password)
authentication so every query runs under the user's own token and
ShotGrid enforces native per-user permissions.

Backend:
- ShotGridAuthClient with connection pooling (LRU, max 200 slots)
- MongoDB session store with TTL-indexed collections
- AbstractSessionStore ABC for swappable backends
- ShotGridCredentials dataclass (SOLID Open/Closed design)
- JWT mint/validate/refresh/revoke via PAT login flow
- Endpoints: /auth/login, /auth/me, /auth/refresh, /auth/logout
- Production hardening: strict JWT_SECRET_KEY, corrupt session cleanup,
  pool release logging, ProdtrackProviderBase as proper ABC

Frontend:
- ShotGridAuthContext with mount-time token validation and auto-refresh
- ShotGridLoginPage (email + password form)
- Default VITE_AUTH_PROVIDER set to shotgrid

Removed (out of PAT scope): Redis, Google OAuth, AMI callback, SSO/OAuth2

Closes AcademySoftwareFoundation#55

Signed-off-by: Srijan <srijan9211@gmail.com>
Resolve two leftover conflict markers (AuthContext.tsx, shotgrid.py).

AuthContext — NoopAuthProviderInner storage fix:
- All reads, writes and clears now use sessionStorage consistently;
  previously token was read from sessionStorage but written to localStorage
  on sign-in and removed from localStorage on sign-out, causing silent
  logout on every page reload and sign-out leaving the token in place
- Fix indentation of useState/useEffect blocks broken during merge

ShotGridAuthContext — mount validation overhaul:
- Parse /auth/me 200 response and call persist() so user state is
  restored even when USER_KEY is absent (e.g. cleared by another tab)
- Replace inline sessionStorage calls in validation path with clear()
  so future changes to clear() apply everywhere automatically
- Remove racing apiHandler.setUser restore effect; validation effect now
  handles all cases (200 ok, 401/403, network error, 5xx) in one place
- Add timer cancel inside clear() so auto-refresh stops on logout/401

Backend:
- Add default values to ShotGridCredentials.username and access_token so
  sessions stored before these fields were added deserialise safely
  instead of raising TypeError and being silently deleted on deploy
- Guard auth_provider is not None before calling get_user_email() in
  get_current_user to prevent AttributeError 500 when provider is absent

    Closes AcademySoftwareFoundation#55

    Signed-off-by: Srijan <srijan9211@gmail.com>
@linux-foundation-easycla

linux-foundation-easycla Bot commented May 26, 2026

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

endpoint and refreshed periodically. Used when connecting via
``session_token=`` (pool path) rather than login+password.
refresh_token : ShotGrid refresh token — used to obtain a new access_token.
password : Legacy Login password — stored because shotgun_api3 requires

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is strange the SG needs the password for the legacy flow and we cannot just get a token and use that everywhere. I do see why it is saved here so the user just needs to authenticate once on the FE. That being said it is dangerus to save a password this way and it should be encrypted. I want to bring in @loorthu to help review this and maybe suggest other ways to handling it so we do not need to store the password at all.

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.

2 participants