Skip to content

Switch SiS demo to OAuth session token auth#63

Draft
j-seuren wants to merge 5 commits intoJetBrains:mainfrom
j-seuren:j-seuren/sis-oauth-session-token-auth
Draft

Switch SiS demo to OAuth session token auth#63
j-seuren wants to merge 5 commits intoJetBrains:mainfrom
j-seuren:j-seuren/sis-oauth-session-token-auth

Conversation

@j-seuren
Copy link

Summary

Switch the Snowflake demo from password-based service user auth to OAuth session token auth in Streamlit-in-Snowflake. The app now authenticates as the logged-in user by reading the SPCS-provided token from /snowflake/session/token, eliminating stored credentials.

Draft: Pending end-to-end validation in a SiS deployment before merging.

Changes

OAuth session token authentication

Monkey-patches SnowflakeIntrospector._connect when running in SiS to use authenticator=oauth with a fresh token on every connection (avoids ~1h expiry).

Files
  • examples/demo-snowflake-project/src/databao_snowflake_demo/app.py
  • examples/demo-snowflake-project/databao/domains/root/src/snowflake.yaml

Remove service user infrastructure

Drops the service user, network policy, and user/password/account secrets from setup/cleanup SQL.

Files
  • examples/demo-snowflake-project/setup.sql
  • examples/demo-snowflake-project/cleanup.sql

Documentation update

Updates README to reflect the new auth model and note that users need USAGE grants.

Files
  • examples/demo-snowflake-project/README.md

Test Plan

  • uv run ruff check passes
  • uv run pytest tests/ -v — 65/65 pass
  • Deploy to SiS and verify OAuth token auth works end-to-end

🤖 Generated with Claude Code

j-seuren and others added 3 commits March 19, 2026 15:54
Replace password-based service user authentication with OAuth session
token auth in the Streamlit-in-Snowflake demo. The app now reads the
SPCS-provided token from /snowflake/session/token on every connection,
authenticating as the logged-in Snowflake user.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The YAML now includes `authenticator: externalbrowser` so local dev
works out of the box with Snowflake SSO. In SiS, the monkey-patch
overrides this with OAuth token auth.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Switches the Streamlit-in-Snowflake (SiS) demo from stored Snowflake service-user credentials to using the SiS-provided OAuth session token so the app authenticates as the logged-in Snowflake user.

Changes:

  • Monkey-patches SnowflakeIntrospector._connect in SiS to connect with authenticator=oauth + fresh token read from /snowflake/session/token.
  • Removes service-user / network-policy setup and deletes datasource credential secrets from setup/cleanup SQL.
  • Updates demo Snowflake domain config and README to reflect new auth model and required grants.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
examples/demo-snowflake-project/src/databao_snowflake_demo/app.py Adds SiS detection + token-based OAuth connect patch for the Snowflake introspector.
examples/demo-snowflake-project/setup.sql Removes service-user/network-policy provisioning and datasource credential secrets; keeps only warehouse/database config secrets.
examples/demo-snowflake-project/cleanup.sql Removes cleanup steps for the deleted service-user/network-policy resources.
examples/demo-snowflake-project/databao/domains/root/src/snowflake.yaml Switches account env var to SNOWFLAKE_ACCOUNT and uses externalbrowser auth for local runs (overridden in SiS by the patch).
examples/demo-snowflake-project/README.md Updates documentation for token auth, new env vars, and required USAGE grants.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +113 to +114
SnowflakeIntrospector._connect = _sis_connect # type: ignore[assignment]
logger.info("Patched SnowflakeIntrospector._connect for SiS OAuth token auth")
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

Overwriting SnowflakeIntrospector._connect at the class level is a broad monkey-patch (affects all instances in-process) and Streamlit reruns can re-apply it repeatedly. Consider adding an idempotency guard (e.g., a sentinel attribute) and/or preserving the original method so it can be restored if needed (helps avoid surprising behavior in mixed environments/tests).

Copilot uses AI. Check for mistakes.
"""
@contextmanager
def _sis_connect(self: Any, file_config: Any, *, catalog: str | None = None) -> Generator[Any, None, None]:
token = SESSION_TOKEN_PATH.read_text().strip()
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

SESSION_TOKEN_PATH.read_text().strip() can raise (e.g., transient file-not-found/permission issues) and can also produce an empty token; either case will currently bubble up as a low-level exception or a confusing connector auth failure. Consider catching OSError/decode errors, validating the token is non-empty, and raising/logging a clear message that the SiS OAuth session token could not be read from /snowflake/session/token.

Suggested change
token = SESSION_TOKEN_PATH.read_text().strip()
try:
raw_token = SESSION_TOKEN_PATH.read_text()
except (OSError, UnicodeDecodeError) as exc:
msg = (
f"Failed to read SiS OAuth session token from {SESSION_TOKEN_PATH!s}. "
"Ensure the token file exists and is readable inside Snowflake."
)
logger.error(msg, exc_info=True)
raise RuntimeError(msg) from exc
token = raw_token.strip()
if not token:
msg = (
f"SiS OAuth session token file {SESSION_TOKEN_PATH!s} is empty. "
"Connector authentication cannot proceed."
)
logger.error(msg)
raise RuntimeError(msg)

Copilot uses AI. Check for mistakes.
Comment on lines +94 to +95
snowflake.connector.paramstyle = "qmark"
kwargs = file_config.connection.to_snowflake_kwargs()
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

Setting snowflake.connector.paramstyle = "qmark" mutates connector global state for the whole process (including any other Snowflake connections Streamlit may open). If this is only needed for the introspector connection, consider limiting the scope (set/restore around the connect) or moving it to a one-time initialization with a clear comment explaining why the global change is safe here.

Copilot uses AI. Check for mistakes.
j-seuren and others added 2 commits March 25, 2026 10:43
Instead of pre-filling the password field with the env var value
(which gets sent to the browser), show a disabled field with a
placeholder indicating the env var is in use.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The agent executes SQL through DuckDB's Snowflake extension (separate
from the introspector path). The default adapter doesn't support OAuth
token auth, so we monkey-patch _create_secret_sql and
_create_connection_string to inject the SPCS session token.

Also adds the SNOWFLAKE_HOST parameter to both patches — Snowflake docs
state the SPCS token can only be used with the SPCS-provided host
endpoint. Corrects README claims about owner's rights vs caller's rights.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

3 participants