{"slug": "how-v0-authenticates-to-snowflake-without-exposing-the-user-s-oauth-token", "title": "How v0 authenticates to Snowflake without exposing the user's OAuth token", "summary": "Vercel's v0 platform now authenticates to Snowflake without exposing user OAuth tokens to generated code, using a request proxy built on the Vercel Sandbox firewall that resolves credentials at request time outside the sandbox runtime. The proxy derives the Snowflake account host from server-side credentials and rejects invalid account URLs, preventing generated code from accessing raw provider credentials.", "body_md": "AI-generated applications often need to authenticate to external services on behalf of their users. That creates a problem: generated code shouldn't have access to the user's credentials.\n\nWe faced that decision when building the v0 [Snowflake integration](https://v0.app/docs/snowflake). It lets users connect Snowflake, inspect schemas, query data, and generate applications that run against their warehouses. That generated code has to authenticate to Snowflake, but it is written by a model and runs without human review, and [prompt injection can steer it into exfiltrating whatever it can read](https://vercel.com/blog/security-boundaries-in-agentic-architectures), so the user's OAuth token should never enter the environment the code runs in.\n\nWe solved this with a Snowflake request proxy for v0 sandboxes, built on the [Vercel Sandbox firewall](https://vercel.com/docs/sandbox/concepts/firewall#requests-proxying). The sandbox can run normal Snowflake clients, but the real credential is resolved at request time in a server proxy outside the sandbox runtime. This lets existing Snowflake clients work inside the sandbox without exposing the user's credential to generated code.\n\nThe harder problem was deciding where the proxy could safely inject the credential. The obvious implementation, replacing a placeholder token wherever it appears, introduces another credential leak.\n\n[v0](https://v0.app/) runs generated applications in isolated sandboxes. Isolation protects the rest of the system from untrusted code, but it doesn't protect secrets inside the sandbox.\n\nIf a generated app can read a token from the filesystem, that token can be copied into logs, returned in an API response, embedded into generated client code, or sent to another host. Sandbox isolation limits what the application can access, but it does not help once the credential itself is available inside the sandbox.\n\nFor Snowflake, the credential represents the Snowflake role the user connected with. v0 should be able to help the user explore and build with data they are authorized to access, but generated code should not receive raw provider credentials just because it needs one.\n\nThe sandbox cannot talk to Snowflake directly. When code inside it sends a request to the user's Snowflake account host, the sandbox firewall forwards that request to the v0 Snowflake proxy:\n\nThe firewall terminates TLS with a certificate authority unique to each sandbox, which lets the proxy read and rewrite traffic that would otherwise be encrypted. The sandbox trusts that certificate authority automatically, so the Snowflake SDK and CLI run with their default certificate validation, OCSP included. The proxy then verifies the sandbox's OIDC token, looks up the v0 chat the sandbox belongs to, restores the user session bound to that chat, and retrieves a fresh Snowflake credential for that user.\n\nThe sandbox does not choose where a token-bearing request is sent. The proxy derives the Snowflake account host from the server-side credential and rejects invalid account URLs, keeping the credential scoped to the connected Snowflake account rather than trusting host information supplied by generated code.\n\nAs a stopgap, the first version of the integration wrote the user's real token into the sandbox's Snowflake token files. The proxy replaced that approach. Ideally, we would remove token files from the sandbox entirely, but Snowflake clients expect credentials in different locations depending on the authentication flow.\n\nSome requests, such as [Snowflake SQL API](https://docs.snowflake.com/en/developer-guide/sql-api/index) calls, authenticate with an `Authorization: Bearer`\n\nheader. Other client flows read local token files and send the token as part of a login request. Once the client has authenticated, subsequent requests use Snowflake-issued session tokens, and the proxy passes those requests through untouched.\n\nTo preserve compatibility, v0 still writes a token-shaped placeholder into the sandbox. The placeholder is a fixed, public, 72-byte string that grants no access, and its only job is to let existing Snowflake SDK and CLI flows behave as if a token exists. The proxy never authorizes a request based on the placeholder itself. Instead, the proxy authorizes the request using the sandbox's server-side identity and its binding to the user's chat.\n\nThe real OAuth token, the reusable credential that represents the user, is never written into the sandbox. Snowflake does issue session tokens that live inside the sandbox after login, but each of those belongs to a single authenticated session.\n\nThose sessions are short-lived in practice. The Snowflake helper in generated apps destroys its connection after each query, which ends the session right away. Closing the chat does not end a session on its own, but tearing down the sandbox takes the token with it, and Snowflake expires the session server-side after four hours of inactivity by default. When a request reaches the proxy, it decides whether and where to attach the credential.\n\nThe first version of the proxy searched each request for the placeholder and swapped in the real token wherever it appeared:\n\nThe problem is that generated code controls parts of the request, including where the placeholder can appear. A SQL statement, for example, is caller-controlled data. If a query contains the placeholder as a string literal, blind replacement turns that query into one containing the real OAuth token. If the database then returns that string, the real token comes back into the sandbox as query output, and the proxy would have leaked the token it was built to keep out.\n\nStricter matching does not close the hole. The proxy shouldn't inject a credential based on attacker-controlled text. Instead, it needs to know which field in each Snowflake request carries authentication.\n\nSnowflake requests reach the proxy in three shapes, and each shape puts authentication in a different place.\n\nFor Snowflake SQL API requests, the proxy sets the OAuth token on the `Authorization: Bearer`\n\nheader. The body remains caller-controlled SQL and is not rewritten. If the placeholder appears in the SQL payload, the proxy rejects the request before it reaches Snowflake and logs it as placeholder misuse.\n\nFor Snowflake login requests, the proxy parses the JSON request body, sets the token structurally at the login token field, and serializes the body again. If the placeholder remains anywhere else in the request body, the proxy fails closed.\n\nPost-login session requests authenticate with Snowflake-managed session tokens, so the proxy has nothing to inject.\n\nThe proxy rejects any request where:\n\nThe sandbox is not bound to a chat\n\nNo user-scoped credential can be obtained\n\nThe Snowflake account host cannot be derived\n\nThe placeholder appears outside an approved authentication field\n\nA structured login body cannot be parsed safely\n\nRequests are also bounded before inspection so that compressed or oversized bodies cannot turn the proxy into an unbounded parser. Every proxied request emits an observability event with the upstream outcome, status, duration, and injection location. This surfaces misuse and integration failures without exposing secrets.\n\nToken refresh cannot depend on an ambient browser cookie, because proxy requests originate from the sandbox, not from the user's browser session. v0 binds the user session to the sandbox instead, and the proxy mints and refreshes OAuth credentials from that binding.\n\nThe publish path uses [Snowflake CLI](https://docs.snowflake.com/en/developer-guide/snowflake-cli/index) flows with the same credential boundary. Deploy can write the placeholder into credential files, but never the real token.\n\nAfter deployment, the application runs in [Snowpark Container Services](https://docs.snowflake.com/en/developer-guide/snowpark-container-services/overview) and authenticates as its own service user, with a token that Snowflake manages and rotates automatically, mounted at `/snowflake/session/token`\n\n. The user's OAuth token and the v0 proxy are no longer involved.\n\nFor users, none of this is visible. Connect Snowflake, ask v0 to inspect schemas or build an app, preview the result, and deploy when it's ready.\n\nThe security model rests on five rules:\n\nCredential injection happens only at each endpoint's authentication fields\n\nRequests that use the placeholder outside an authentication field are rejected and logged\n\nToken-bearing requests go only to the connected Snowflake account host\n\nCredentials are minted and refreshed server-side\n\nGenerated code uses Snowflake without ever reading the user's OAuth token\n\nIn its first 15 days in production, the proxy attached credentials server-side for roughly 13,000 requests and recorded zero placeholder-misuse rejections.\n\nAlthough we built this proxy for Snowflake, the same problem applies to other integrations: generated code often needs to authenticate without receiving the user's long-lived credential. The important part is to inject credentials only into protocol-defined authentication fields, rather than rewriting arbitrary request data.\n\nThe v0 Snowflake integration is now available in beta. Get started by reading the [integration docs](https://v0.app/docs/snowflake).", "url": "https://wpnews.pro/news/how-v0-authenticates-to-snowflake-without-exposing-the-user-s-oauth-token", "canonical_source": "https://vercel.com/blog/how-v0-authenticates-to-snowflake-without-exposing-the-users-oauth-token", "published_at": "2026-08-20 04:00:00+00:00", "updated_at": "2026-08-20 18:14:05.621294+00:00", "lang": "en", "topics": ["ai-products", "ai-safety", "ai-infrastructure"], "entities": ["Vercel", "v0", "Snowflake", "Vercel Sandbox firewall"], "alternates": {"html": "https://wpnews.pro/news/how-v0-authenticates-to-snowflake-without-exposing-the-user-s-oauth-token", "markdown": "https://wpnews.pro/news/how-v0-authenticates-to-snowflake-without-exposing-the-user-s-oauth-token.md", "text": "https://wpnews.pro/news/how-v0-authenticates-to-snowflake-without-exposing-the-user-s-oauth-token.txt", "jsonld": "https://wpnews.pro/news/how-v0-authenticates-to-snowflake-without-exposing-the-user-s-oauth-token.jsonld"}}