Skip to content

User passthrough integrations

Integrations

A user passthrough integration reaches the upstream as the person using the app, so the upstream’s own permissions apply to them: their mailbox, their row-level security in a warehouse, their records in a CRM. Greenlight’s audit log records every call as theirs.

  • Each person connects once, at the upstream’s own sign-in. Greenlight keeps their token, encrypted, and refreshes it.
  • The app never sees a token. Greenlight’s proxy uses the right person’s token on each call.
  • Any sign-in works. Okta, Microsoft Entra ID, Google or any OpenID Connect provider; the upstream is independent of it.

When a shared service account is enough, a service account integration is simpler. How an integration authenticates compares the three kinds.

Apps write no OAuth code. When a feature needs the person’s account, the app shows a Connect button; Greenlight hosts the rest.

Your appa feature needs theiraccount: ConnectGreenlight Connect pagenames the app, its ownerand the integrationThe upstream's sign-ine.g. Snowflake, Microsoft,Box: sign in, approveBack in the appon the same page;the feature worksclickContinueconnected
What a person sees, once per integration. Greenlight's own pages are outlined in green.
Greenlight's Connect page. The app's icon, Expense Tracker by Jane Doe, sits beside the Snowflake — Analytics logo with an arrow between them. The heading reads Expense Tracker wants to access your Snowflake — Analytics account. Buttons: Continue to Snowflake — Analytics, and Not now.
The Connect page: which app is asking, who owns it, and which account it wants.

Three parties take part, whichever identity provider and upstream you use: the person’s browser, Greenlight, and the upstream. The app never holds a token.

Person's browserGreenlightUpstream's OAuth server1 · clicks Continue: /connect/start2 · redirect to the upstream's sign-inGreenlight's OAuth client, PKCE, login hint3 · signs in and approves access, on the upstream's own pageits MFA and policies apply here4 · redirect back with a one-time code5 · /connect/callback?code=…6 · code + client secretserver to server, never via the browser7 · access token + refresh token8 · checks the account is the signed-in person;stores both tokens encrypted, per person9 · redirect back to the app's page
Connecting, once per person. Greenlight runs the OAuth exchange and keeps the tokens; no token reaches the browser or the app.
More detail: who runs OAuth, and where tokens live
  • Who runs the OAuth flow: Greenlight. It builds the redirect with the OAuth client IT registered, using PKCE and the person’s identity from their Greenlight sign-in as the login hint. It receives the one-time code at its own callback and trades it for tokens server to server, with the client secret it keeps in your vault.
  • What the person sees. Usually nothing: when the browser already has a session at the upstream and the client is consented, the upstream answers at once. Otherwise they see the upstream’s own sign-in, consent or second-factor screen, once.
  • How Greenlight knows the account is theirs. Before storing anything, it compares the account the upstream returned with the person’s Greenlight sign-in: the directory’s tenant and user id where the upstream issues them, otherwise the username or a verified email. A mismatch stores nothing and tells the person which account was refused.
  • Where the tokens live. Encrypted in Greenlight’s database, one connection per person and credential. Greenlight refreshes the access token before it expires and keeps the rotated refresh token. Signing out of Greenlight and back in does not ask the person to connect again.
Person's browsersigned in via your IdPGreenlightsign-in checkThe appholds no upstream tokenGreenlight proxyholds the tokensUpstream APIapplies the person's rights1 · opens a page2 · request + actor tokensigned, minutes-long, names the person3 · data key + actor tokenkey = which app · token = which person4 · verifies both, checks the app's grant,loads this person's stored token,refreshing it if it is about to expire5 · same request, person's token6 · only what they may see7 · answer; audit logs person + app8 · the page
Every call. The data key says which app is calling and the actor token says which person, so the proxy uses that person's own token and the upstream applies their permissions.
More detail: how the proxy knows who is who
  • How the proxy knows who is who. Every request into an app first passes Greenlight’s sign-in check, the same single sign-on that protects every app. It adds a signed, minutes-long actor token naming the person. The app forwards that header unchanged with its own data key: the key says which app, the actor token says which person.
  • What the proxy does. It verifies both, checks that the app holds a grant on the integration, loads that person’s stored token for the granted credential, refreshes it if needed, and makes the call with it.
  • What the app sees. The upstream’s answer and nothing else: no upstream token, no secret.
  • What is refused. A call with no person behind it, such as a scheduled job, because there is nobody to act as; and a call made by an administrator impersonating someone.
  1. Create an OAuth client at the upstream with https://<your Greenlight host>/connect/callback as its redirect URI, and grant admin consent where the upstream offers it.

  2. The Register integration dialog with snowflake typed in the catalog search. One result, the Snowflake tile, appears above the Custom integration option.

    Find it in the catalog. In Integrations → Register integration, search for the upstream, or pick Custom for any other OAuth 2.0 upstream.

  3. The Register Snowflake dialog on its Set up step, with the steps Set up, Name, Connect, Credential and Review, showing the Snowflake setup guide.

    Register it. A catalog entry fills in the URLs and scopes, and a stepped guide walks you through the upstream’s side.

  4. Add the credential: the client’s id and secret. Every app granted it reaches exactly that client’s permissions, as each person.

  5. The Snowflake — Analytics integration card. Its credential warehouse-read has the buttons Test sign-in, Edit and Delete.

    Press Test sign-in on the integration’s card and sign in as yourself. It fails exactly where a person’s connect would, and names the cause and the fix.

  6. Grant it to the apps that need it.

More detail: Custom upstreams, credentials and Test sign-in
  • Custom upstreams. Supply the authorize URL, token URL, the scopes each person authorizes, and optionally a revocation URL on the same server as the token URL. Include openid and email in the scopes, plus profile and offline_access on Microsoft Entra, so Greenlight can confirm the account and request a refresh token. On Microsoft Entra, name your tenant id in the URLs, never /common.
  • One client per permission set. Two apps that need different permissions on the same upstream get two clients, two credentials and two grants.
  • Test sign-in runs the same connect a person runs, so it catches a missing redirect URI, a wrong client id or secret, or missing consent. A pass shows the account Greenlight matched and leaves you connected; the card keeps when it last passed and who tested it. If the upstream shows its own error page instead of coming back, the dashboard lists the usual causes after a minute.
  • Always proxied. Tokens are per person, so there is no single value to put in an app’s environment.
The Test sign-in result for Snowflake — Analytics: Sign-in works. You are connected as yourself. Matched account: JANE.DOE. Button: Close tab.
A passing Test sign-in, with the account Greenlight matched.
Integration Acts as the person in How each person connects
Snowflake SQL statements, in the credential’s role Snowflake’s own sign-in, through your IdP when federated
Microsoft Graph Mail, calendars, OneDrive and SharePoint files, the directory Microsoft sign-in
Microsoft Fabric The REST API, the API for GraphQL, semantic models, SQL endpoints Microsoft sign-in
Box Files and folders No connect step: one enterprise-wide Box app
Custom Any OAuth 2.0 upstream The upstream’s own sign-in

Salesforce and NetSuite list a user passthrough profile that is not selectable yet; register them with client credentials meanwhile. A provider offering both a shared identity and passthrough is registered as two integrations, one per mode, such as salesforce and salesforce-user (Manage integrations).

Snowflake setup

Calls the SQL API (POST /api/v2/statements) as the person, so Snowflake’s own users, roles, grants, masking policies and row access policies decide what each statement sees.

  • Sign-in. Snowflake is its own authorization server. People sign in on Snowflake’s login page, through your identity provider when the account is federated, so it works the same for Okta and Entra organizations with nothing to configure on the identity provider.
  • Registering. The only profile is Per-user OAuth (Snowflake OAuth). Enter your account identifier (<orgname>-<account_name>, not the legacy locator); the form fills in the endpoints.
  • The setup guide renders the CREATE SECURITY INTEGRATION statement with your connect callback in it: a custom confidential client with PKCE enforced and refresh tokens valid for up to 90 days. Read the client id and secret back with SYSTEM$SHOW_OAUTH_CLIENT_SECRETS.
  • People. Each person needs a Snowflake user whose login name is the email they sign in to Greenlight with; the connect step compares the two. Close secondary roles with a session policy, and attach a network policy limiting the integration to your install’s egress addresses.

Each credential is one Snowflake role. The role is fixed once saved, because each person consents to it when they connect; another role is another credential, with the same client id and secret.

  • Greenlight sets each statement’s role to the credential’s role, whatever the app sends, so an app runs in exactly the role its grant approved.
  • ACCOUNTADMIN, SECURITYADMIN, ORGADMIN, GLOBALORGADMIN and quoted role names are refused.
  • Each person sees Snowflake’s consent page once per credential. Access tokens last ten minutes and Greenlight refreshes them.
  • Scheduled work with nobody signed in needs a Snowflake service user, not this profile.
Microsoft Graph setup

Reaches Exchange Online mail, Outlook calendars, OneDrive and SharePoint files, and the directory as the person, through /me/… on graph.microsoft.com. It is offered to every organization, whatever its identity provider: people in an Okta or Google organization sign in to Microsoft on the connect step.

  • Registering. Search the catalog by name or by Outlook, Mail, Calendar, OneDrive or SharePoint, and enter your Entra tenant id. The dialog fills in the endpoints and scopes, and a stepped guide covers the Entra side.
  • One registration per purpose. Each credential is one Entra app registration holding the delegated permissions one purpose needs, such as “Greenlight Mail” with Mail.Send. Entra puts every consented permission into every token it issues, so two apps needing different permissions get two registrations, two credentials and two grants.
  • Consent. Grant admin consent on each registration. Without it people see a consent page, or cannot connect at all where your tenant’s user consent settings exclude the permissions.
  • Policies. A person’s access is the registration’s permissions intersected with their own rights. Conditional Access policies on the services behind the permissions, on all resources and on the registration apply when they connect.

Sending mail is what the entry is built for. POST /v1.0/me/sendMail returns 202, and Exchange saves the message to the person’s Sent Items and routes it through your transport rules and journaling. Sending from a shared mailbox needs Mail.Send.Shared plus Send As or Send on Behalf on the mailbox; without them Graph answers 403 ErrorSendAsDenied.

What the builder agent is told:

  • paging and delta links are absolute graph.microsoft.com URLs, called through the proxy, never followed directly;
  • a 429 carries Retry-After and the app backs off, since the proxy does not retry;
  • a drive item’s /content answers 302 to a short-lived URL, which the proxy passes through.

App-only Graph access is not user passthrough: the Microsoft Teams entry and the Graph entry’s Application permissions (app-only) profile act as the app (Manage integrations).

Microsoft Fabric setup

One Microsoft Fabric tile registers everything apps need from one Entra app registration, in four steps:

  1. Set up: tick REST and GraphQL, Semantic models (DAX) and SQL endpoints as needed.
  2. Connect: enter the Entra tenant id and each SQL endpoint’s host and database; Greenlight checks it can reach them.
  3. Credential: enter the application (client) id and the client secret once.
  4. Review, then Register.

Register creates one integration per ticked piece and one per SQL endpoint, each with its own credential, grants and per-person connection: microsoft-fabric-user, power-bi-semantic-models, and fabric-sql-<database>-user. If one fails, for example because a SQL host is unreachable, Review says which; fix it and press Register again, and only the missing ones are registered. The picker also finds the tile by Power BI, GraphQL, DAX, semantic model, Warehouse, Lakehouse, SQL database and OneLake. Scheduled jobs use the same form with the type set to Service identity, which registers a service principal instead.

The dialog lists only the steps for what you ticked. Open a step’s Details for the reasons, or Copy steps to paste the list into a ticket or an agent.

Before you register, in Entra and on your network:

  1. Register a dedicated single-tenant app, such as “Greenlight Fabric”. Never reuse the Greenlight sign-in app.
  2. Under API permissions, add the delegated permissions and grant admin consent:
    • REST and GraphQL: Power BI Service Workspace.Read.All and Item.Read.All, plus GraphQLApi.Execute.All for the API for GraphQL;
    • semantic models: Power BI Service Dataset.Read.All;
    • SQL endpoints: Azure SQL Database user_impersonation.
  3. Under Authentication, add the web redirect URI https://<your Greenlight host>/connect/callback.
  4. Under Certificates & secrets, create a client secret and copy its value.
  5. For SQL endpoints, copy each item’s host and database from Settings → SQL connection string.
  6. Only for a private install whose outbound traffic leaves through your firewall: allow login.microsoftonline.com on 443, api.fabric.microsoft.com on 443 for REST and GraphQL, api.powerbi.com on 443 for semantic models, and each SQL endpoint host on TCP 1433 as MSSQL/TDS, not HTTPS.
  7. Only if a workspace has IP firewall rules (Workspace settings → Inbound networking): add Greenlight’s outbound address. On a private install behind your firewall it is the firewall’s public address; otherwise it is the cluster network’s outbound address, in your cloud console.

Give people access, in Fabric and Entra:

  1. REST and GraphQL: give each person a workspace role (Viewer is least privilege) or item permission. For each API for GraphQL item, choose single sign-on under Settings → Connectivity and share it with Run Queries and Mutations.
  2. Semantic models: turn on the Dataset Execute Queries REST API tenant setting for a group of the people who use the apps, give each person Read and Build on the model (never Write), and on a model with row-level security add each person to a role on its Security page.
  3. SQL endpoints: share each item with the people who use it, then narrow with T-SQL GRANT; on a Lakehouse SQL analytics endpoint, choose its access mode deliberately.
  4. Review the Conditional Access policies on Power BI Service, Azure SQL Database, All resources and the app registration; each person meets them when they connect.

REST and GraphQL reach https://api.fabric.microsoft.com/v1/… and the API for GraphQL as the person, who sees exactly the workspaces and items their role or item permission allows.

  • None of the service-principal setup applies: not the Service principals can use Fabric APIs setting, its security group or the 30-day bootstrap. A person without a Fabric license is refused by Fabric itself.
  • A GraphQL item must use single sign-on for queries to run as the person; with saved credentials every person sees the same rows. An Azure SQL Database source supports saved credentials only.
  • The agent calls the item at ${GREENLIGHT_PROXY_URL}/<integration>/v1/workspaces/<workspace-id>/graphqlapis/<id>/graphql, and is told the limits: read-only sources behind a SQL analytics endpoint, 64 MB and 100 seconds per response, query depth 10, introspection off by default.
  • Fabric list responses page with continuationUri and long-running operations answer 202 Location; both are followed through the proxy as the same person.
Power BI semantic models setup

Runs DAX as the person through POST /v1.0/myorg/datasets/<id>/executeQueries on https://api.powerbi.com, so the model’s row-level security filters every result to what they may see. A service principal cannot query a row-level-security model at all, which is why this integration acts as the person.

  • Who is filtered. Row-level security applies only to people with Read or Build and nothing more: Write, and the Admin, Member and Contributor workspace roles, bypass it.
  • Roles. On a model with row-level security, put each person, or a group they belong to, in one of its roles on the Security page; otherwise every query fails with RLSNotAuthorizedForModel. Role members in a deployed model file may not carry over, so check that page after each deployment.
  • Limits. One DAX query per call; 100,000 rows or 1,000,000 values and 15 MB per query; 120 requests per minute per person; DAX only. The agent never sends impersonatedUserName.
Fabric SQL endpoints setup

Each SQL endpoint is a connected database for one host and database, queried as the person over TDS on port 1433, so its own row-level security, column security, masking and workspace roles apply:

Item Host Database
Warehouse, Lakehouse SQL analytics endpoint <id>.datawarehouse.fabric.microsoft.com the item name
Fabric SQL database <id>.database.fabric.microsoft.com the <name>-<guid> in its connection string
  • Calling it. Apps send { sql, params } to POST ${GREENLIGHT_PROXY_URL}/<integration>/query with the inbound actor token.
  • Idle endpoints. An endpoint nobody has used for a while can be slow to accept the next connection; Greenlight keeps trying for up to 30 seconds, so the first query waits instead of failing.
  • Permission. The token is for Azure SQL Database, so the registration needs delegated user_impersonation with admin consent. Someone with no workspace role or item permission is refused at login, and the app receives 403 proxy.upstream_user_unmapped.
  • Masking. Workspace Admins, Members and Contributors see past dynamic data masking, but T-SQL row-level security still filters their rows.
  • Lakehouse access mode. Delegated identity reads OneLake as the item owner, so SQL grants, row-level security and masking are the only bounds; user’s identity applies OneLake security roles and ignores table GRANTs.
  • Connections. Each person’s queries run on SQL connections opened with their own token and used by nobody else: at most two per person, closed after five idle minutes, never reused past the token’s expiry. Revoking someone’s connection closes them on their next call. inspectIntegrationDb runs as the developer making the call.
Box setup

Reaches Box files and folders as the person, so each call sees exactly what they can open in Box. Box accepts no outside sign-in, so there is no connect step and no per-person token at rest: IT registers one Box app with Client Credentials Grant, and on every call Greenlight finds the Box account whose login is the person’s email and asks Box for a token for that account. The profile is named “Client Credentials Grant (as the user)”.

Setting it up, following the stepped guide in the Register dialog:

  1. Create a Server Authentication (Client Credentials Grant) app in the Box Developer Console.
  2. Set App + Enterprise Access, and choose the content scopes apps need plus Manage users, which Greenlight needs to find each person’s account.
  3. Turn on Generate user access tokens; leave Make API calls using the as-user header off.
  4. Have a Box admin authorize the app in Admin Console → Platform → Platform Apps, and Reauthorize it after any change to its scopes or access level.
  5. Enter the app’s Client ID and Enterprise ID, and paste its Client Secret. A mistyped Enterprise ID refuses everyone; correct it by editing the integration.

Box refusing to issue a token, usually because the app is not authorized in Platform Apps or Generate user access tokens is off, returns 502 proxy.upstream_auth_failed. A file’s /content answers 302 to a short-lived dl.boxcloud.com URL, which the proxy passes through. Uploads to upload.box.com do not go through this integration. Every call is audited as the person, with their Box login and user id.

  • People disconnect their own connections; IT revokes any person’s through the API (DELETE /api/users/<id>/connections), and deactivating a person deletes theirs.
  • Deleting a credential or its integration revokes every connection made through it.
  • Every revocation is audited. Greenlight deletes its copy of the token, tells the upstream where it offers revocation, and refuses the next proxy call.
More detail: reconnecting, pruning, and what apps may store
  • Connecting again replaces the previous authorization. Connections with neither a sign-in nor an update for ninety days are pruned.
  • What an app reads as one person stays theirs. Anything an app caches or stores from these calls is keyed by the person it was read as and shown only to them, never pooled into a shared table or served to a colleague. Work for several people runs once per person, as each of them; a view across people needs a service-account integration IT granted for that purpose.
What a person sees when connecting does not work
What happened What the person sees
They have not connected yet The app’s Connect button, which opens the Connect page
Their connection stopped working The same button and page, worded Reconnect
They declined, or chose the wrong account Greenlight’s result page, with Try again and Back to the app
The upstream sent an error back The result page, with the upstream’s code in a line for IT
A setup error kept the upstream from sending them back The upstream’s own error page; next time, the Connect page says what to tell IT
Greenlight's result page after a failed connect. The heading reads Connecting Snowflake — Analytics did not work. The text says nothing was saved and the rest of the app still works. A line for IT names the upstream's answer, invalid_client. Buttons: Try again, and Back to the app.
If the upstream sends an error back: what happened, and the upstream's code for IT.

Behind the button, the proxy answers 401 proxy.user_connection_required with a connect_url (error reference). The Builder Skill gives apps the button and its states, so an app never sends anyone to the upstream without a click. Several integrations on one app each get their own button.

If the upstream refuses to issue a token because an administrator has not consented to the client, the proxy answers 502 proxy.upstream_auth_failed and names the client. Connecting again would not fix that, so Greenlight does not ask the person to.