Secure GraphRAG: Wiring Microsoft Copilot Studio to Neo4j with per-user Okta SSO Microsoft Copilot Studio can now be wired to Neo4j with per-user Okta SSO, enabling identity-scoped GraphRAG where the database enforces access based on the signed-in user's Okta groups mapped to Neo4j roles. The integration forwards each user's Okta access token through a Neo4j MCP server on Google Cloud Run, avoiding the security risks of shared service accounts. This approach ensures that AI-generated Cypher queries return only data the user is authorized to see, addressing the confused deputy problem in AI agents. Secure GraphRAG: Wiring Microsoft Copilot Studio to Neo4j with per-user Okta SSO 13 min read More in this guide: Graph access that knows who you are. A financial advisor asks Copilot, “Which of my clients have more than 30% of their portfolio concentrated in a single sector and haven’t rebalanced in over 90 days?” Answering that means traversing clients to accounts to holdings to securities to transaction history, several hops deep, and the advisor should see exactly their own book of business. Once an LLM is writing the queries, you can’t fully predict or constrain what it will ask for. If the agent connects to Neo4j with a single shared service account, every user’s session inherits whatever that account can reach, and one bad generation can walk straight into a colleague’s clients. Most Copilot-to-database integrations get built this way anyway, because a shared service account is the fastest way to get a demo working. It holds up right until more than one type of user touches it in production. A more robust solution would be to have Copilot Studio calling a Neo4j MCP server that forwards each user’s own Okta access token straight through to Neo4j, with Okta groups mapped to Neo4j roles so the database enforces who sees what. Your Neo4j instance needs SSO with Okta already configured before you start, since this integration extends that existing trust relationship instead of creating it. Why per-user identity matters more for AI agents than for regular apps In a typical application, your code decides what queries run and enforces authorization above the database. A user can’t ask the app to do something it wasn’t built to do. An AI agent breaks that assumption, because the agent writes the query itself in response to whatever the person types. Ask an LLM to “show me what’s relevant to this deal” and it might traverse into a subgraph the person asking was never supposed to reach. If that agent connects with a shared service account, it becomes what security engineers call a confused deputy. It holds more authority than the person prompting it, and it uses that authority on their behalf whether or not it should. Pushing identity down to Neo4j closes that gap. The agent can still generate any Cypher it wants, but the signed-in user’s own roles decide what actually comes back. A bad generation can’t return more than that person is already allowed to see. Identity-scoped retrieval means the agent sometimes returns less than it technically “could,” and two different people can get two different answers to the same question. That’s the access model working as intended. If your team spends an afternoon debugging why the agent gave inconsistent answers, check who was signed in before you check the prompt. The advisor scenario above is specific, but the same mechanism applies to any graph, whether it holds portfolios, patient records, or supply chain data. Okta groups map to Neo4j roles, Neo4j enforces the boundary, and Copilot only ever surfaces what the signed-in user’s role allows. What you’re actually building A Copilot Studio agent uses OAuth 2.0 to get an Okta access token on behalf of the signed-in user, passes that token as a bearer header to the Neo4j MCP server running on Google Cloud Run, and the MCP server forwards the token unchanged to Neo4j. Neo4j validates the token directly against Okta and maps the user’s Okta groups to database roles. The only credential anywhere on that path is the Okta-issued bearer token. The key architectural decision: the Neo4j instance validates the Okta-issued access token directly — not through Neo4j’s Auth0 broker. By default, Neo4j’s Aura console SSO trusts broker-issued tokens. Copilot sends a raw Okta token, so you configure the database to also accept the Okta issuer directly. That’s the database-side change that makes the whole chain work. Before you start Your Neo4j database must already have SSO configured with Okta before you start this integration. You’ll need: Neo4j Enterprise or Aura at a tier that supports Instance SSO — AuraDB Business Critical or AuraDB Virtual Dedicated Cloud. The instance must have been created after SSO was configured SSO doesn’t retroactively apply to older instances . Alternatively, you could also implement the same configuration using a Neo4j self-managed instance. Neo4j instance configured for SSO with Okta via Organization → Security → Single Sign-On, using the your Neo4j SSO Okta app Okta app with redirect https://login.neo4j.com/login/callback and Instance SSO enabled. Neo4j Aura Organization Owner or Admin access , plus Okta admin access. GCP project with Cloud Run enabled and gcloud CLI access to deploy the MCP server image. Microsoft Copilot Studio with permission to add MCP tools using the Streamable HTTP transport. Database authentication and role mapping The Neo4j instance needs to be configured ot validate the Okta authorization server directly for database authentication: - Issuer: https://