Skip to content

Commit bfd582a

Browse files
Merge pull request #69 from aaguiarz/feat/openfga-support
Add OpenFGA Support for Local Development in FastMCP FGA example
2 parents adaa55d + 14e8a8a commit bfd582a

9 files changed

Lines changed: 165 additions & 73 deletions

File tree

auth-for-mcp/fastmcp-mcp-fga-js/.env.example

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@ AUTH0_AUDIENCE=
33
PORT=3001
44
MCP_SERVER_URL=http://localhost:3001
55

6-
# Get these from dashboard.fga.dev / Store Settings
6+
# For Auth0 FGA Get these from dashboard.fga.dev / Store Settings
77
FGA_API_URL='https://api.us1.fga.dev'
88
FGA_STORE_ID=<store_id>
99
FGA_API_TOKEN_ISSUER='auth.fga.dev'
1010
FGA_API_AUDIENCE='https://api.us1.fga.dev/'
1111
FGA_CLIENT_ID='<client_id>'
1212
FGA_CLIENT_SECRET='<client_secret>'
13+
14+
# For OpenFGA
15+
FGA_API_URL='https://api.us1.fga.dev'
16+
FGA_STORE_ID=<store_id>

auth-for-mcp/fastmcp-mcp-fga-js/README.md

Lines changed: 89 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ with Auth0 using the [FastMCP](https://github.com/punkpeye/fastmcp) TypeScript f
55

66
This repository shows a minimal but realistic integration with:
77
- OAuth 2.0 / OIDC via Auth0 for authentication and token verification
8-
- Auth0 FGA (OpenFGA) for fine-grained Resource Authorization
8+
- Auth0 FGA or OpenFGA for fine-grained Resource Authorization
99
- FastMCP for exposing tools as MCP endpoints
1010

1111
This example uses an authorization model defined in [`fga/model.fga`](./fga/model.fga) that supports:
@@ -21,16 +21,16 @@ with Auth0 using the [FastMCP](https://github.com/punkpeye/fastmcp) TypeScript f
2121
- Node.js 18+
2222
- npm (or a compatible package manager)
2323
- An Auth0 tenant (for OAuth and token verification)
24-
- An Auth0 FGA account (OpenFGA / fga.dev) for authorization model and tuples
25-
- `fga` CLI (optional, for bootstrapping the model and tuples)
24+
- Either an Auth0 FGA account ([fga.dev](https://fga.dev)) OR a local OpenFGA instance for authorization
25+
- `fga` CLI (for managing the authorization model and tuples)
2626

2727
## Available Tools
2828

2929
The server exposes the following tools:
3030

3131
- `whoami` - Returns authenticated user information and granted scopes
3232
- `greet` - Personalized greeting demonstrating authenticated tool access
33-
- `get_datetime` Returns the current UTC date and time (no scope required)
33+
- `get_datetime` - Returns the current UTC date and time (no scope required)
3434
- `get_documents` - Returns a list of documents from a mock API. Depending on the user role, it will return private documents or not.
3535

3636
## Install dependencies
@@ -45,15 +45,13 @@ npm install
4545

4646
For detailed instructions on setting up your Auth0 tenant for MCP server integration, please refer to the [Auth0 Tenant Setup guide](https://github.com/auth0-samples/auth0-ai-samples/tree/main/auth-for-mcp/fastmcp-mcp-js/README.md#auth0-tenant-setup) in the FastMCP example.
4747

48-
## Auth0 FGA Setup
48+
## FGA Setup
4949

5050
Auth0 FGA provides fine-grained authorization using [Relationship-Based Access Control (ReBAC)](https://docs.fga.dev/concepts#what-is-relationship-based-access-control-rebac). It's built on [OpenFGA](https://openfga.dev), a CNCF incubation project, and offers more flexible authorization patterns than traditional RBAC.
5151

5252
### Prerequisites
5353

54-
1. **Create an Auth0 FGA Account**: Sign up for free at [fga.dev](https://fga.dev)
55-
2. **Generate API Credentials**: Follow [this guide](https://docs.fga.dev/intro/settings) to create credentials with full permissions
56-
3. **Install the FGA CLI**:
54+
1. **Install the FGA CLI**:
5755
```bash
5856
# macOS
5957
brew install openfga/tap/fga
@@ -62,41 +60,75 @@ Auth0 FGA provides fine-grained authorization using [Relationship-Based Access C
6260
# https://github.com/openfga/cli/releases
6361
```
6462

65-
### CLI Configuration
63+
#### To use Auth0 FGA
6664

67-
After creating your FGA credentials, export the following (provided during credential creation):
65+
1. **Create an Auth0 FGA Account**: Sign up for free at [fga.dev](https://fga.dev)
66+
2. **Generate API Credentials**: Follow [this guide](https://docs.fga.dev/intro/settings) to create credentials with full permissions
67+
3. **Create CLI environment variables**: Configure the CLI to use the proper configuration values:
6868

69-
```bash
70-
export FGA_API_URL='https://api.us1.fga.dev'
71-
export FGA_STORE_ID='<your-store-id>'
72-
export FGA_API_TOKEN_ISSUER='auth.fga.dev'
73-
export FGA_API_AUDIENCE='https://api.us1.fga.dev/'
74-
export FGA_CLIENT_ID='<your-client-id>'
75-
export FGA_CLIENT_SECRET='<your-client-secret>'
76-
```
69+
```bash
70+
export FGA_API_URL='https://api.us1.fga.dev'
71+
export FGA_STORE_ID='<your-store-id>'
72+
export FGA_API_TOKEN_ISSUER='auth.fga.dev'
73+
export FGA_API_AUDIENCE='https://api.us1.fga.dev/'
74+
export FGA_CLIENT_ID='<your-client-id>'
75+
export FGA_CLIENT_SECRET='<your-client-secret>'
76+
```
7777

78-
### Authorization Model
78+
4. **Import the authorization model and tuples**:
7979

80+
```bash
81+
fga store import --file fga/store.fga.yaml
82+
```
8083

81-
### Initial Setup
84+
#### To use OpenFGA
8285

83-
1. **Deploy the Authorization Model**:
84-
```bash
85-
fga model write --file ./fga/model.fga
86-
```
86+
1. **Start OpenFGA**: Run it as a binary or using Docker.
8787

88-
2. **Import Initial Data**: The [`fga/tuples.yaml`](./fga/tuples.yaml) file defines:
89-
- Two roles: `admin` and `content_manager`
90-
- Two groups: `marketing` (content_manager role) and `managers` (admin role)
91-
- Tool permissions:
92-
- Everyone: `get_datetime`
93-
- Admin & Content Manager: `greet`, `whoami`, `get_documents`
94-
- Admin only: Can view private documents
88+
Using [Homebrew](https://brew.sh/) (or download the binaries from the [OpenFGA releases page](https://github.com/openfga/openfga/releases/)):
89+
90+
```bash
91+
brew install openfga
92+
```
93+
94+
Start OpenFGA:
95+
```bash
96+
openfga run
97+
```
98+
99+
Or use Docker:
100+
101+
```bash
102+
docker run -p 8080:8080 -p 8081:8081 -p 3000:3000 openfga/openfga run
103+
```
95104

96-
Import the tuples:
97-
```bash
98-
fga tuple write --file ./fga/tuples.yaml
99-
```
105+
106+
2. **Bootstrap a new store**: Import the authorization model and initial tuples:
107+
108+
```bash
109+
fga store import --file fga/store.fga.yaml
110+
```
111+
112+
This will create a new store and return output like:
113+
```json
114+
{
115+
"store": {
116+
"created_at":"0001-01-01T00:00:00Z",
117+
"id":"01KB0NZZFAV9AX7SAPWY23KJAF",
118+
"name":"",
119+
"updated_at":"0001-01-01T00:00:00Z"
120+
},
121+
"model": {
122+
"authorization_model_id": "01KED54TEMBDE753YBK7NT3DRZ"
123+
}
124+
}
125+
```
126+
127+
3. **Configure environment variables**: Use the store ID from the output above:
128+
129+
```bash
130+
export FGA_STORE_ID='<your-store-id>'
131+
```
100132

101133
### Managing User Access
102134

@@ -152,26 +184,37 @@ After modifying permissions, test with different users to verify:
152184
4. **User with No Assignments**:
153185
- Should see: `get_datetime` only
154186

155-
You can also manage tuples directly in the [Auth0 FGA Dashboard](https://dashboard.fga.dev) for.
187+
You can also manage tuples directly in the [Auth0 FGA Dashboard](https://dashboard.fga.dev) for real-time testing and debugging.
156188

157189
## Configuration
158190

159-
Rename `.env.example` to `.env` and configure the domain and audience:
191+
Rename `.env.example` to `.env` and configure your environment:
160192

161-
```
193+
### Common Configuration (Required)
194+
```bash
162195
# Auth0 tenant domain
163196
AUTH0_DOMAIN=example-tenant.us.auth0.com
164197

165198
# Auth0 API Identifier
166199
AUTH0_AUDIENCE=http://localhost:3001/
200+
```
167201

168-
# FGA Configuration
169-
FGA_API_URL='https://api.us1.fga.dev'
170-
FGA_STORE_ID=<store_id>
171-
FGA_API_TOKEN_ISSUER='auth.fga.dev'
172-
FGA_API_AUDIENCE='https://api.us1.fga.dev/'
173-
FGA_CLIENT_ID='<client_secret>'
174-
FGA_CLIENT_SECRET='<client_secret>'
202+
### Auth0 FGA Configuration
203+
If using Auth0 FGA, add these variables:
204+
```bash
205+
FGA_API_URL=https://api.us1.fga.dev
206+
FGA_STORE_ID=<your-store-id>
207+
FGA_API_TOKEN_ISSUER=auth.fga.dev
208+
FGA_API_AUDIENCE=https://api.us1.fga.dev/
209+
FGA_CLIENT_ID=<your-client-id>
210+
FGA_CLIENT_SECRET=<your-client-secret>
211+
```
212+
213+
### OpenFGA Configuration
214+
If using OpenFGA locally, add these variables:
215+
```bash
216+
FGA_API_URL=http://localhost:8080
217+
FGA_STORE_ID=<your-store-id>
175218
```
176219

177220
With the configuration in place, the example can be started by running:
@@ -214,3 +257,4 @@ curl -X POST http://localhost:3001/mcp \
214257
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
215258
-d '{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "get_datetime", "arguments": {}}}'
216259
```
260+

auth-for-mcp/fastmcp-mcp-fga-js/fga/add-temporal-access.sh

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@
77
# Prerequisites:
88
# - Auth0 CLI installed and authenticated (auth0 login)
99
# - FGA CLI installed (fga)
10-
# - FGA_STORE_ID environment variable set
11-
#
10+
# - For Auth0 FGA:
11+
# FGA_API_URL, FGA_STORE_ID, FGA_API_TOKEN_ISSUER, FGA_API_AUDIENCE, FGA_CLIENT_ID and FGA_CLIENT_SECRET environment variables set
12+
# - For OpenFGA:
13+
# - FGA_STORE_ID environment variable set
14+
1215
# Usage:
13-
# ./add-temporal-access.sh <email> <tool-name> <duration-seconds>
16+
# ./fga/add-temporal-access.sh <email> <tool-name> <duration-seconds>
1417
#
1518
# Example:
16-
# ./add-temporal-access.sh peter@gmail.com greet 3600s
17-
# ./add-temporal-access.sh alice@company.com whoami 7200s
19+
# ./fga/add-temporal-access.sh peter@gmail.com greet 3600s
20+
# ./fga/add-temporal-access.sh alice@company.com whoami 7200s
1821

1922
set -e
2023

auth-for-mcp/fastmcp-mcp-fga-js/fga/add-user-to-group.sh

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@
77
# Prerequisites:
88
# - Auth0 CLI installed and authenticated (auth0 login)
99
# - FGA CLI installed (fga)
10-
# - FGA_STORE_ID environment variable set
11-
#
10+
# - For Auth0 FGA:
11+
# FGA_API_URL, FGA_STORE_ID, FGA_API_TOKEN_ISSUER, FGA_API_AUDIENCE, FGA_CLIENT_ID and FGA_CLIENT_SECRET environment variables set
12+
# - For OpenFGA:
13+
# - FGA_STORE_ID environment variable set#
1214
# Usage:
13-
# ./scripts/add-user-to-group.sh <email> <group-name>
15+
# ./fga/add-user-to-group.sh <email> <group-name>
1416
#
1517
# Example:
16-
# ./scripts/add-user-to-group.sh peter@gmail.com marketing
18+
# ./fga/add-user-to-group.sh peter@gmail.com marketing
19+
# ./fga/add-user-to-group.sh andres.aguiar@gmail.com marketing
1720

1821
set -e
1922

auth-for-mcp/fastmcp-mcp-fga-js/fga/remove-user-from-group.sh

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77
# Prerequisites:
88
# - Auth0 CLI installed and authenticated (auth0 login)
99
# - FGA CLI installed (fga)
10-
# - FGA_STORE_ID environment variable set
11-
#
10+
# - For Auth0 FGA:
11+
# FGA_API_URL, FGA_STORE_ID, FGA_API_TOKEN_ISSUER, FGA_API_AUDIENCE, FGA_CLIENT_ID and FGA_CLIENT_SECRET environment variables set
12+
# - For OpenFGA:
13+
# - FGA_STORE_ID environment variable set#
1214
# Usage:
13-
# ./scripts/remove-user-from-group.sh <email> <group-name>
15+
# ./fga/remove-user-from-group.sh <email> <group-name>
1416
#
1517
# Example:
16-
# ./scripts/remove-user-from-group.sh peter@gmail.com marketing
18+
# ./fga/remove-user-from-group.sh peter@gmail.com marketing
1719

1820
set -e
1921

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
11

2+
#!/bin/bash
3+
4+
# This script resets all tuples in the FGA store, by deleting all tuples and re-adding them from the tuples file.
5+
#
6+
# Prerequisites:
7+
# - Auth0 CLI installed and authenticated (auth0 login)
8+
# - FGA CLI installed (fga)
9+
# - For Auth0 FGA:
10+
# FGA_API_URL, FGA_STORE_ID, FGA_API_TOKEN_ISSUER, FGA_API_AUDIENCE, FGA_CLIENT_ID and FGA_CLIENT_SECRET environment variables set
11+
# - For OpenFGA:
12+
# - FGA_STORE_ID environment variable set#
13+
# Usage:
14+
# ./fga/reset-tuples.sh
15+
216
fga tuple read --output-format=simple-json --max-pages=0 > tuples.json
317
fga tuple delete --file tuples.json
418
fga tuple write --file tuples.yaml
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
model_file: model.fga
2+
tuple_file: tuples.yaml
3+
tests:
4+
- check:
5+
- user: user:anne
6+
object: tool:get_datetime
7+
assertions:
8+
can_use: true

auth-for-mcp/fastmcp-mcp-fga-js/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

auth-for-mcp/fastmcp-mcp-fga-js/src/openfga.ts

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,26 +34,40 @@ const FGA_API_TOKEN_ISSUER = process.env.FGA_API_TOKEN_ISSUER;
3434
const FGA_API_AUDIENCE = process.env.FGA_API_AUDIENCE;
3535
const FGA_CLIENT_ID = process.env.FGA_CLIENT_ID;
3636
const FGA_CLIENT_SECRET = process.env.FGA_CLIENT_SECRET;
37+
const FGA_API_TOKEN = process.env.FGA_API_TOKEN;
3738

38-
if (!FGA_API_URL || !FGA_STORE_ID || !FGA_API_TOKEN_ISSUER || !FGA_API_AUDIENCE || !FGA_CLIENT_ID || !FGA_CLIENT_SECRET) {
39+
if (!FGA_API_URL || !FGA_STORE_ID ) {
3940
throw new Error(
40-
"FGA configuration missing: FGA_API_URL, FGA_STORE_ID, FGA_API_TOKEN_ISSUER, FGA_API_AUDIENCE, FGA_CLIENT_ID, and FGA_CLIENT_SECRET are required"
41+
"FGA configuration missing: FGA_API_URL, FGA_STORE_ID are required"
4142
);
4243
}
4344

44-
// Initialize OpenFGA client with Auth0 FGA credentials
45+
// Initialize OpenFGA client. If FGA_API_TOKEN is provided, use it; if client_id is specified, use it, if not, do not use authentication
4546
let fgaClient = new OpenFgaClient({
4647
apiUrl: FGA_API_URL,
4748
storeId: FGA_STORE_ID,
48-
credentials: {
49-
method: CredentialsMethod.ClientCredentials,
50-
config: {
51-
apiTokenIssuer: FGA_API_TOKEN_ISSUER,
52-
apiAudience: FGA_API_AUDIENCE,
53-
clientId: FGA_CLIENT_ID,
54-
clientSecret: FGA_CLIENT_SECRET,
55-
},
56-
},
49+
...(FGA_API_TOKEN
50+
? {
51+
credentials: {
52+
method: CredentialsMethod.ApiToken,
53+
config: {
54+
token: FGA_API_TOKEN,
55+
},
56+
},
57+
}
58+
: FGA_CLIENT_ID
59+
? {
60+
credentials: {
61+
method: CredentialsMethod.ClientCredentials,
62+
config: {
63+
apiTokenIssuer: FGA_API_TOKEN_ISSUER ?? '',
64+
apiAudience: FGA_API_AUDIENCE ?? '',
65+
clientId: FGA_CLIENT_ID,
66+
clientSecret: FGA_CLIENT_SECRET ?? '',
67+
},
68+
},
69+
}
70+
: {}),
5771
});
5872

5973
/**

0 commit comments

Comments
 (0)