Skip to main content
Fine-grained authorization goes beyond simple scope-based access control by enabling sophisticated permission models based on relationships between users, roles, groups, and resources. This quickstart demonstrates how to use Auth0 FGA to implement Relationship-Based Access Control (ReBAC) for your MCP server tools. The sample application showcases five authorization patterns:
  1. Public Tools - Accessible to all authenticated users without additional permissions
  2. Role-Based Access - Tools assigned to specific roles (admin, content_editor)
  3. Group Membership - Users inherit permissions through group membership (managers, marketing)
  4. Temporal Access - Time-limited tool access with automatic expiration
  5. Resource-Specific Permissions - Fine-grained control over tool features (e.g., viewing private documents)
By the end of this quickstart, you will have an MCP server that:
  • Authenticates users with Auth0 OAuth 2.0
  • Uses Auth0 FGA to determine which tools each user can access
  • Dynamically filters tool lists based on user permissions
  • Supports time-limited access grants that automatically expire
  • Provides different data based on user roles (public vs private documents)

Prerequisites

Auth for MCP is currently available in Early Access. To join the Early Access program, please complete this form. We’ll reach out to you when your request is processed.
To continue with this quickstart, you need to have an Auth0 account.
To use the resource parameter in your access tokens, you need to enable the compatibility profile.The quickest way to enable it is through the Auth0 Dashboard:
  1. Navigate to Settings on the left sidebar.
  2. Click on Advanced in the top right corner.
  3. Scroll down to the Settings section, find and enable the Resource Parameter Compatibility Profile toggle.
This guide uses Auth0 CLI to configure an Auth0 tenant for secure MCP tool access.
  1. Follow the Auth0 CLI installation instructions.
  2. Log in to your account with the Auth0 CLI:
auth0 login --scopes "read:client_grants,create:client_grants,delete:client_grants,read:clients,create:clients,update:clients,read:resource_servers,create:resource_servers,update:resource_servers,read:roles,create:roles,update:roles,update:tenant_settings,read:connections,update:connections"
Confirm you are in the correct tenant by double-checking the tenant domain in the terminal, or run the command below:
auth0 tenants list
If more than one tenant is configured, the default tenant will be indicated by an arrow.
To simplify the process of interacting with the Auth0 CLI, we recommend installing jq. This will allow you to easily parse JSON responses from the CLI.
brew install jq
Now install and setup the dependencies for FGA:
This guide uses the OpenFGA CLI to manage authorization models and permissions.
  1. Install the FGA CLI:
brew install openfga/tap/fga
  1. Verify the installation:
fga version
You’ll need an Auth0 FGA or OpenFGA store to manage fine-grained authorization for your MCP tools.Choose your FGA provider:
  • Auth0 FGA: Fully managed service at fga.dev. Best for production use.
  • OpenFGA: Self-hosted open-source option. Best for local development and testing.
Both options use the same authorization model and API. You can start with OpenFGA locally and migrate to Auth0 FGA for production.
The sample application includes a complete authorization model (fga/model.fga) and initial permission tuples (fga/tuples.yaml) that will be imported using the FGA CLI.

Configure tenant settings

To allow third-party clients like MCP Inspector to use a connection such as a username-and-password database or a social connection, you need to promote the connection to a domain-level connection. Learn more about enabling third-party applications.
1

List Your Connection

List your connections to get their IDs
auth0 api get connections
2

Choose Your Connections

From the list, identify which connections you want to use for the MCP server and copy the ID.
  • For the username-and-password database, look for the connection with the strategy auth0.
  • For the Google social connection, look for the connection with the strategy google-oauth2.
3

Upgrade the Connection to Domain-Level

For each of those specific connection IDs, run the following command to mark it as a domain-level connection. Replace YOUR_CONNECTION_ID with the actual ID (e.g., con_XXXXXXXXXXXXXXXX).
auth0 api patch connections/YOUR_CONNECTION_ID --data '{"is_domain_connection": true}'

Create an API to represent your MCP server

An MCP server is treated just like any other API in your Auth0 tenant, which means you can use the same access control, scoping, and authorization features. The API (also known as a Resource Server) represents your protected MCP Server. Run the following command to create an API in Auth0:
auth0 api post resource-servers --data '{
  "identifier": "http://localhost:3001/",
  "name": "MCP Tools API",
  "signing_alg": "RS256",
  "token_dialect": "rfc9068_profile_authz",
  "enforce_policies": true,
  "scopes": [
    {"value": "tool:whoami", "description": "Access the WhoAmI tool"},
    {"value": "tool:greet", "description": "Access the Greeting tool"}
  ]
}'
Note that rfc9068_profile_authz is used as the token dialect to include the permissions claim in the access token, which can be useful for the API to check user permissions without making additional calls. For more details on protecting APIs with Auth0, check our quickstarts.
This quickstart uses two OAuth scopes for demonstration: tool:greet and tool:whoami. The get_datetime tool is public and doesn’t require scopes, while get_documents uses FGA for authorization.

Set up your FGA store

1

Create an Auth0 FGA account

Sign up for a free account at fga.dev.
2

Create a store

In the Auth0 FGA dashboard, create a new store for your MCP server.
3

Generate API credentials

  1. Navigate to Settings in your store.
  2. In the Authorized Clients section, click + Create Client.
  3. Give your client a name and select the following permissions:
    • Read/Write model, changes, and assertions - To query authorization decisions
    • Write and delete tuples - To import tuples (user permissions)
    • Read and query - To import the authorization model
  4. Click Create.
  5. Save the credentials shown in the confirmation modal.
4

Configure environment variables

Set the following environment variables in your terminal. These will be used by the FGA CLI to connect to your store.
export FGA_API_URL='https://api.us1.fga.dev'
export FGA_STORE_ID='<your-store-id>'
export FGA_API_TOKEN_ISSUER='auth.fga.dev'
export FGA_API_AUDIENCE='https://api.us1.fga.dev/'
export FGA_CLIENT_ID='<your-client-id>'
export FGA_CLIENT_SECRET='<your-client-secret>'
Replace the placeholders with the credentials from the previous step. Note that FGA_API_URL may vary based on your region (e.g., api.eu1.fga.dev for Europe).

Sample app

Start by downloading or cloning the sample app for this quickstart. The sample includes a FastMCP MCP server with Auth0 OAuth and Auth0 FGA integration in JavaScript/TypeScript.

Install packages

Install the required dependencies:
npm install

Create your environment file

From the root of your sample app directory, run the following command to create a new .env file with your Auth0 configuration:
DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name') \
&& touch .env \
&& echo "AUTH0_DOMAIN=${DOMAIN}" > .env \
&& echo "AUTH0_AUDIENCE=http://localhost:3001/" >> .env \
&& echo "PORT=3001" >> .env \
&& echo "MCP_SERVER_URL=http://localhost:3001" >> .env \
&& echo "" >> .env \
&& echo ".env file created with your Auth0 configuration:" \
&& cat .env
Next, add your FGA configuration to the .env file. The variables you need depend on which FGA provider you’re using:
Add the following to your .env file using the credentials from your Auth0 FGA store:
.env
# Auth0 FGA Configuration
FGA_API_URL=https://api.us1.fga.dev
FGA_STORE_ID=YOUR_STORE_ID
FGA_API_TOKEN_ISSUER=auth.fga.dev
FGA_API_AUDIENCE=https://api.us1.fga.dev/
FGA_CLIENT_ID=YOUR_CLIENT_ID
FGA_CLIENT_SECRET=YOUR_CLIENT_SECRET
Replace:
  • YOUR_STORE_ID with your store ID from the Auth0 FGA dashboard
  • YOUR_CLIENT_ID with your client ID
  • YOUR_CLIENT_SECRET with your client secret
  • Update FGA_API_URL if your store is in a different region (e.g., https://api.eu1.fga.dev for Europe)
Your complete .env file should look like this:
.env
AUTH0_DOMAIN=YOUR_TENANT.us.auth0.com
AUTH0_AUDIENCE=http://localhost:3001/
PORT=3001
MCP_SERVER_URL=http://localhost:3001

# Auth0 FGA Configuration
FGA_API_URL=https://api.us1.fga.dev
FGA_STORE_ID=YOUR_STORE_ID
FGA_API_TOKEN_ISSUER=auth.fga.dev
FGA_API_AUDIENCE=https://api.us1.fga.dev/
FGA_CLIENT_ID=YOUR_CLIENT_ID
FGA_CLIENT_SECRET=YOUR_CLIENT_SECRET

Understanding the authorization model

The authorization model in this sample demonstrates how Auth0 FGA provides fine-grained access control using Relationship-Based Access Control (ReBAC).

Authorization Model Structure

The complete model is defined in fga/model.fga:
model
  schema 1.1

  type user

  # User groups
  type group
    relations
      define member : [user]

  # Roles can be linked to users or members of a user group
  type role
    relations
      define assignee : [user, group#member]

  type tool
    relations
      # Public access, role-based, and temporal access
      define can_use : [user:*, user, role#assignee, user with temporal_access, role#assignee with temporal_access]

      # Resource-specific permission for get_documents tool
      define can_view_private_documents : [role#assignee]

  # Temporal access condition
  condition temporal_access(grant_time: timestamp, grant_duration: duration, current_time: timestamp) {
    current_time < grant_time + grant_duration
  }
The model defines four authorization patterns:
Tools that are accessible to all authenticated users without requiring specific permissions.
# In fga/tuples.yaml
- user: user:*
  relation: can_use
  object: tool:get_datetime
The wildcard user:* means any authenticated user can use the get_datetime tool.
Tools are assigned to specific roles, and users with those roles can access the tools.
# In fga/tuples.yaml
# Admin role can use all tools
- user: role:admin#assignee
  relation: can_use
  object: tool:greet

- user: role:admin#assignee
  relation: can_use
  object: tool:whoami

- user: role:admin#assignee
  relation: can_use
  object: tool:get_documents
Users assigned the admin role automatically gain access to these tools.
Users inherit permissions through group membership. Groups are assigned to roles, creating a permission chain.
# In fga/tuples.yaml
# Managers group is assigned the admin role
- user: group:managers#member
  relation: assignee
  object: role:admin

# Marketing group is assigned the content_editor role
- user: group:marketing#member
  relation: assignee
  object: role:content_editor
Permission Chain: User → Group → Role → ToolWhen you add a user to the managers group, they automatically inherit all permissions of the admin role, including access to all tools.
Time-limited access to tools that automatically expires after a specified duration.
// In fga/model.fga
condition temporal_access(grant_time: timestamp, grant_duration: duration, current_time: timestamp) {
  current_time < grant_time + grant_duration
}

// Tools can be assigned with temporal conditions
define can_use : [user:*, user, role#assignee, user with temporal_access, role#assignee with temporal_access]
When you grant temporal access (e.g., “20 seconds to use the greet tool”), FGA evaluates the condition on each request. Access is automatically revoked when the time expires.
Fine-grained permissions for specific features or data within tools.
# In fga/tuples.yaml
# Admin role can view private documents
- user: role:admin#assignee
  relation: can_view_private_documents
  object: tool:get_documents
The get_documents tool checks this permission separately to determine whether to return private documents. This allows the same tool to provide different data based on user permissions.Example:
  • Admin role: Sees all documents (public + private)
  • Content editor role: Sees only public documents

How Authorization Works

When a user connects to the MCP server:
  1. The server authenticates the user with Auth0 (validates JWT token)
  2. The server queries FGA to get all tools the user can access:
    • Checks can_use relation for each tool
    • Evaluates group memberships, role assignments, and temporal conditions
  3. The server returns only authorized tools to the MCP client
  4. When the user calls a tool like get_documents, the server checks can_view_private_documents to determine what data to return
This approach ensures that authorization decisions are centralized in FGA and can be updated dynamically without changing code.

Import the authorization model and tuples

The sample includes a complete authorization model and initial permission tuples that define:
  • Public access to get_datetime for all users
  • Role assignments (admin, content_editor)
  • Group-to-role mappings (managersadmin, marketingcontent_editor)
  • Tool access permissions for each role
1

Review the authorization model

The authorization model is defined in fga/model.fga. It includes types for users, groups, roles, and tools, plus a temporal access condition.The initial tuples are defined in fga/tuples.yaml and establish the baseline permissions.
2

Import the model and tuples

From the root of your sample app directory, run:
fga store import --file fga/store.fga.yaml
This command will:
  1. Create a new FGA store (if using OpenFGA locally)
  2. Upload the authorization model from fga/model.fga
  3. Import the initial tuples from fga/tuples.yaml
  4. Run tests defined in fga/store.fga.yaml to verify the setup
If using OpenFGA, the command output will include a store ID. Copy this ID and add it to your .env file as FGA_STORE_ID. If using Auth0 FGA with existing store, the command will update your store with the new model and tuples.
3

Verify the import

If the import is successful, you should see output similar to:
{
  "store": {
    "id": "01KB0NZZFAV9AX7SAPWY23KJAF",
    "name": "fastmcp-fga-example",
    "created_at": "2025-01-22T10:30:00Z",
    "updated_at": "2025-01-22T10:30:00Z"
  },
  "model": {
    "authorization_model_id": "01KED54TEMBDE753YBK7NT3DRZ"
  }
}
The tests at the end should show all checks passing, confirming that the authorization model is working correctly.
You can view and manage your authorization model in the Auth0 FGA Dashboard if you’re using Auth0 FGA. The dashboard provides a visual Model Explorer and allows you to view, add, and delete tuples in real-time.

Run the MCP server

Start the MCP server:
npm run start
The server will start on port 3001 (or the port specified in your .env file). You should see console output indicating:
  • The server has started successfully
  • FGA client has been initialized
  • The server is listening for connections at http://localhost:3001/mcp
FastMCP Auth0 Example Server started
FGA client initialized for store: 01KB0NZZFAV9AX7SAPWY23KJAF
Server listening on http://localhost:3001/mcp
Leave the server running for testing in the next sections.

Manage user permissions

The sample application includes helper scripts in the fga/ directory to make permission management easier. These scripts use the FGA CLI to add or remove authorization tuples dynamically.

Available Scripts

Grant a user all permissions associated with a group (and its assigned role).Usage:
./fga/add-user-to-group.sh <user-email> <group-name>
Examples:
# Add user to managers group (grants admin role with full access)
./fga/add-user-to-group.sh user@example.com managers

# Add user to marketing group (grants content_editor role)
./fga/add-user-to-group.sh user@example.com marketing
What it does: Creates an FGA tuple that makes the user a member of the specified group. Since groups are assigned to roles, the user automatically inherits all role permissions.Available groups:
  • managers - Assigned to admin role (all tools + private documents)
  • marketing - Assigned to content_editor role (all tools, public documents only)
Revoke a user’s group membership and all associated permissions.Usage:
./fga/remove-user-from-group.sh <user-email> <group-name>
Example:
# Remove user from managers group
./fga/remove-user-from-group.sh user@example.com managers
What it does: Deletes the FGA tuple that grants group membership. The user immediately loses all permissions from that group’s role.
Provide time-limited access to a specific tool that automatically expires.Usage:
./fga/add-temporal-access.sh <user-email> <tool-name> <duration>
Examples:
# Grant 20-second access to the greet tool
./fga/add-temporal-access.sh user@example.com greet 20s

# Grant 1-hour access to the whoami tool
./fga/add-temporal-access.sh user@example.com whoami 1h

# Grant 5-minute access
./fga/add-temporal-access.sh user@example.com greet 5m
What it does: Creates an FGA tuple with a temporal condition. FGA evaluates the condition on each request and automatically denies access when the duration expires. No cleanup is needed.Supported durations: Use standard time notation (s for seconds, m for minutes, h for hours).Available tools: greet, whoami, get_documents
Public tools like get_datetime don’t need temporal access grants since they’re already accessible to all authenticated users.
Reset all tuples to the initial state defined in fga/tuples.yaml.Usage:
./fga/reset-tuples.sh
What it does: Deletes all existing tuples and reimports the default tuples from fga/tuples.yaml. Useful for returning to a clean state during testing.
This script removes all user assignments, including any custom permissions you’ve added. Use with caution.

Testing Permission Changes

After running any of these scripts, you need to reload the tools:
  • for MCP inspector: click ‘Clear’ in the MCP inspector tools panel and then ‘List Tools’
  • for other MCP clients: you might need to reconnect the MCP Client to see the updated tool list.
The server queries FGA on each connection to determine available tools.
You can also manage tuples directly in the Auth0 FGA Dashboard if you’re using Auth0 FGA. The dashboard provides a visual interface for viewing, adding, and removing authorization tuples in real-time.

Testing your MCP server

Now that your MCP server is up and running, you can test it by using tools like MCP Inspector.

Learn how to test your Auth0-powered MCP server

Test authorization scenarios

Now test different authorization scenarios to see how FGA controls tool access. You’ll need to use an MCP client like MCP Inspector to connect to your server.
1

Test baseline access

Connect to your MCP server using your user credentials. Initially, you should only see the public tool.Expected tools: get_datetimeThis demonstrates that without any role or group assignments, authenticated users only have access to public tools.
2

Grant admin access via managers group

Add your user to the managers group to grant admin role permissions:
./fga/add-user-to-group.sh YOUR_EMAIL managers
Replace YOUR_EMAIL with the email address you use to authenticate.Reconnect in your MCP client and verify you now see all tools.Expected tools: get_datetime, greet, whoami, get_documentsCall the get_documents tool and verify that you see both public and private documents in the response. This demonstrates resource-specific permissions based on the admin role.
In MCP Inspector, you’ll need to disconnect and reconnect (or refresh the connection) after changing permissions. The server queries FGA on each new connection to determine available tools.
3

Test content editor role

Switch from admin to content editor by changing group membership:
./fga/remove-user-from-group.sh YOUR_EMAIL managers
./fga/add-user-to-group.sh YOUR_EMAIL marketing
Reconnect in your MCP client.Expected tools: get_datetime, greet, whoami, get_documentsCall the get_documents tool and verify that you now see only public documents (no private documents). This demonstrates how the same tool can provide different data based on user roles.Key difference: Content editors have access to the same tools as admins but don’t have the can_view_private_documents permission.
4

Test temporal access

Remove all group memberships and grant time-limited access to a specific tool:
./fga/remove-user-from-group.sh YOUR_EMAIL marketing
./fga/add-temporal-access.sh YOUR_EMAIL greet 20s
This grants 20 seconds of access to the greet tool.Immediately reconnect in your MCP client.Expected tools: get_datetime, greetCall the greet tool to verify it works.Wait 25 seconds and reconnect again.Expected tools: get_datetime (only)The greet tool should no longer appear. This demonstrates automatic expiration of temporal access without any cleanup required.
Temporal access is evaluated in real-time on each request. Once the duration expires, FGA automatically denies access even if the tuple still exists in the database.

Next steps