DEV Community

Yolanda Robla Mota for Stacklok

Posted on

How to use Okta to remotely authenticate to your BigQuery MCP Server

This article builds on our previous post, where we explored the high-level architecture of token exchange, identity federation, and how to run MCP servers in a secure and IdP-agnostic way. Now we shift into the hands-on phase: how to use ToolHive to enable an MCP server to query Google BigQuery for users authenticated via Okta. While we use Okta and Google Cloud as the example stack, this flow is adaptable to any IdP and any cloud provider with a compatible STS / federation service.

Scenario overview

  • You run an MCP server that receives requests from users who are authenticated via Okta.
  • The MCP server must execute queries in Google Cloud BigQuery.
  • You don’t want to manage Google service-account keys, embed JSON credentials in config, or lose per-user audit.
  • You want: user-level attribution, least-privilege roles, secure, short-lived access, and federation between Okta and Google Cloud.

In this example, we’re implementing the IdP federation approach described as scenario “B” in the previous blog post. The diagram below shows how ToolHive, Okta, and Google Cloud interact in this flow.

IDP federation diagram

Prerequisites

Before you start, make sure you have:

  • Okta admin access: You’ll need permissions to create an OIDC app and an authorization server.
  • A Google Cloud project: With BigQuery enabled and permissions to create a Workforce Identity Pool.
  • ToolHive CLI: download it from toolhive.dev and confirm it’s in your system path.
  • Container runtime: Docker, Podman, or Rancher Desktop are supported.
  • An MCP client such as Claude Code (or any other client supporting the MCP protocol).

Detailed configuration steps

Step 1: Configure Okta as Identity Provider

  1. In the Okta Admin Console, navigate to Applications → Applications and click Create App Integration. See https://help.okta.com/en-us/content/topics/apps/apps_app_integration_wizard_oidc.htm
  2. Choose OIDC – OpenID Connect and then Web Application for the app type.
  3. Configure the sign-in redirect URI to http://localhost:8666/callback (this is the callback needed for the MCP server that we will run later using ToolHive).

IMPORTANT: Note the client ID and client secret; you’ll need them in later steps.

Okta client

Step 2: Create an Authorization Server in Okta

Your OIDC app issues tokens via an Authorization Server. For the Workforce Federation and token exchange, you need one configured correctly.

  1. In the Okta Admin Console, Navigate to Security → API → Authorization Servers.
  2. Click Add Authorization Server.
  3. Name: BigQuery MCP Server (or any descriptive name)
  4. Audience: set this to match the audience expected by your MCP server configuration (for example, mcpserver).
  5. Click Save.
  6. Configure an additional gcp.access scope:
    Okta scopes

  7. And the access policies for the types of tokens to generate, including Token Exchange:
    Okta rules

With this setup, Okta will:

  • Issue standards-compliant OIDC tokens to your MCP server through ToolHive.
  • Include the claims Google Cloud expects during the token exchange.

IMPORTANT: Note the issuer URL for the Authorization Server, you’ll need it in the next steps.

Step 3: Create Workforce Identity Pool in Google Cloud

  1. In the Google Cloud console, create a Workforce Identity Pool and a matching provider, using the Issuer URL you noted in the previous step:
    Workforce identity pool

  2. Define custom audiences. The Okta client ID needs to be passed as an audience, so start by copying the default audience. Then select Allowed audiences, add the default value, and include your Okta client ID as well.

Allowed audiences

  1. Configure permissions for the Okta user so they can read BigQuery data. Repeat this for each user you want to map:
gcloud projects add-iam-policy-binding <PROJECT_NAME> \
--member="principalSet://iam.googleapis.com/projects/<PROJECT_ID>/locations/global/workloadIdentityPools/okta-pool/attribute.email/<MAPPED_OKTA_EMAIL>" \
--role="roles/bigquery.dataViewer"
Enter fullscreen mode Exit fullscreen mode

Step 4: Deploy MCP server + proxy with remote authentication via ToolHive

In this step, we bring together the MCP server and the remote authentication/federation flow. Using ToolHive, we’ll run the server and wrap it with a proxy that handles user authentication with Okta and token exchange into Google Cloud.

Start by creating a group. ToolHive automatically manages clients registered to your default group, adding or removing MCP servers as you run them. Since this server will sit behind an authenticated proxy, we don’t want that auto-configuration behavior, so we’ll create a separate group for it instead:

thv group create toolbox-group
Enter fullscreen mode Exit fullscreen mode

Then start the open source MCP Toolbox for Databases server using the ToolHive CLI. ToolHive automatically pulls the server image using metadata from the ToolHive registry. You can view details about the image with thv registry info database-toolbox.

thv run --group toolbox-group database-toolbox \
--env BIGQUERY_PROJECT=<YOUR_PROJECT_ID> \
--env BIGQUERY_USE_CLIENT_OAUTH=true \
--proxy-port 6000 \
-- --prebuilt bigquery --address 0.0.0.0
Enter fullscreen mode Exit fullscreen mode

Here’s what each parameter does:
--group toolbox-group: Name of the ToolHive group that the MCP server belongs to
database-toolbox: The MCP server image from the ToolHive registry
--env BIQUERY_PROJECT: Your Google Cloud project ID containing BigQuery resources
--env BIGQUERY_USE_CLIENT_OAUTH=true: Use the OAuth flow instead of static service account credentials
--proxy-port: Port exposed on your host for the containerized MCP server
--: CLI arguments passed into the MCP server
--prebuilt bigquery: Use the prebuilt configuration for BigQuery
--address 0.0.0.0: Bind the server to all network interfaces so the proxy can reach it

ToolHive spins up the MCP server container and HTTP proxy process, ready to handle BigQuery queries using the MCP protocol. Using ToolHive ensures the server is containerized, isolated, and managed securely — avoiding the “run-it-manually” friction.

Next, the thv proxy command starts a proxy process that sits in front of the MCP server and handles all incoming requests. It prompts you to sign in with Okta, exchanges your Okta token for a Google Cloud access token, and then forwards your request to the MCP server using that token.

thv proxy \
  --target-uri http://127.0.0.1:6000 \
  --remote-auth-client-id <OKTA_CLIENT_ID> \
  --remote-auth-client-secret <OKTA_CLIENT_SECRET> \
  --remote-auth okta \
  --remote-auth-issuer <AUTHORIZATION_SERVER_URL> \
  --remote-auth-callback-port 8666 \
  --remote-auth-scopes 'openid,profile,email,gcp.access' \
  --port 62614 \
  --token-exchange-url https://sts.googleapis.com/v1/token \
  --token-exchange-scopes 'https://www.googleapis.com/auth/bigquery,https://www.googleapis.com/auth/cloud-platform' \
  --token-exchange-audience //iam.googleapis.com/projects/<GOOGLE_PROJECT_NUMBER>/locations/global/workloadIdentityPools/okta-pool/providers/okta-provider
Enter fullscreen mode Exit fullscreen mode

Here’s what each flag does:
--target-uri: Points to the MCP server’s proxy port (from the previous step)
--remote-auth-client-id: Client ID of your Okta app (from step 1)
--remote-auth-client-secret: Client secret of your Okta app (from step 1)
--remote-auth okta: Specifies the remote auth provider
--remote-auth-issuer: URL of the Okta authorization server’s issuer (from step 2)
--remote-auth-callback-port: Local port used for the OAuth callback (must match the callback URL used in step 1)
--remote-auth-scopes: Scopes requested from Okta during authentication
--port: Port the ToolHive proxy exposes to clients
--token-exchange-url: Google STS endpoint for exchanging tokens
--token-exchange-scopes: Google Cloud scopes required to access BigQuery and related APIs
--token-exchange-audience: Google Workload Identity Pool audience for Okta federation

When your browser opens, sign in with Okta. The proxy uses your Okta credentials to generate ID tokens, exchange them for valid Google tokens with the right scopes, and then continues the request automatically.

Step 5: Run the MCP server with Claude or another client

Let’s use Claude Code as an example. Because ToolHive doesn’t automatically manage client configurations for proxied MCP servers, you’ll need to add it manually:

# Add the authenticated ToolHive proxy
claude mcp add --scope user --transport http database-toolbox http://127.0.0.1:62614/mcp

# Run Claude Code
claude
Enter fullscreen mode Exit fullscreen mode

The Toolbox MCP server uses the token provided by the ToolHive proxy and passes it to Google Cloud, giving you access to the resources available to your account.

Any other MCP-compatible client can connect the same way. Just point it to the ToolHive proxy endpoint.

Claude and MCP

Why this architecture is powerful

  • Simple for clients: Apps connect to the ToolHive proxy just like any other MCP server endpoint.
  • Secure authentication flow: The proxy makes you log in through Okta, so every request carries a verified user identity.
  • Federated access to Google Cloud: Instead of embedding service account keys in your server, the proxy handles a token exchange so Google recognizes your identity through the workforce identity provider.
  • Least-privilege and auditable: BigQuery jobs run under your federated Okta identity, so logs show “user@domain.com ran a BigQuery job” rather than “service-account X”.
  • Separation of concerns: The MCP server (Toolbox) focuses on data tools and queries, while the proxy handles auth, token exchange, and routing. It’s a cleaner, safer architecture.

Of course, it’s easy to get started with ToolHive, since it’s free and open source. I encourage you to visit toolhive.dev, where you can download the project and explore our docs.

Top comments (0)