Skip to content

Commit 22a60d7

Browse files
dgellowclaude
andauthored
Multi-IDP support (#33)
## Summary - Replace Google-specific OAuth with a provider abstraction supporting Google, Azure AD, GitHub, and generic OIDC - Separate authentication (identity fetching) from authorization (access policy) so IDP errors and policy rejections produce distinct error types - Systematic quality pass: fix bugs, unify patterns, reduce complexity ## Breaking change Config format changes from flat `googleClientId`/`googleClientSecret` fields to a structured `idp` block: ```json "idp": { "provider": "google|azure|github|oidc", "clientId": "...", "clientSecret": {"$env": "..."}, "redirectUri": "..." } ``` ## Quality improvements - Fix duplicate `isStdioServer` with diverging implementations - Unify CSRF tokens to stateless HMAC approach (removes `sync.Map` leak) - Make `StoreAuthorizeRequest` return error (Firestore failures were silent) - Fix SameSite cookie mismatch (Strict → Lax for OAuth callbacks) - Add `GetUser` to Storage interface for O(1) admin checks - Split oversized files, consolidate tiny packages, delete dead code Closes #31, closes #29 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 21929b3 commit 22a60d7

File tree

90 files changed

+6068
-4092
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+6068
-4092
lines changed

CLAUDE.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -245,23 +245,24 @@ When refactoring for better design:
245245

246246
```bash
247247
# Build everything
248-
make build
248+
./scripts/build
249249

250250
# Format everything
251-
make format
251+
./scripts/format
252252

253253
# Lint everything
254-
make lint
254+
./scripts/lint
255255

256256
# Test mcp-front
257+
./scripts/test
257258
go test ./internal/... -v
258259
go test ./integration -v
259260

260261
# Run mcp-front locally
261262
./mcp-front -config config.json
262263

263264
# Start docs dev server
264-
make doc
265+
./scripts/docs
265266
```
266267

267268
## Documentation Site Guidelines

cmd/mcp-front/main.go

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,42 @@ func generateDefaultConfig(path string) error {
2222
"addr": ":8080",
2323
"name": "mcp-front",
2424
"auth": map[string]any{
25-
"kind": "oauth",
26-
"issuer": "https://mcp.yourcompany.com",
27-
"allowedDomains": []string{"yourcompany.com"},
28-
"allowedOrigins": []string{"https://claude.ai"},
29-
"tokenTtl": "24h",
30-
"storage": "memory",
31-
"googleClientId": map[string]string{"$env": "GOOGLE_CLIENT_ID"},
32-
"googleClientSecret": map[string]string{"$env": "GOOGLE_CLIENT_SECRET"},
33-
"googleRedirectUri": "https://mcp.yourcompany.com/oauth/callback",
34-
"jwtSecret": map[string]string{"$env": "JWT_SECRET"},
35-
"encryptionKey": map[string]string{"$env": "ENCRYPTION_KEY"},
25+
"kind": "oauth",
26+
"issuer": "https://mcp.yourcompany.com",
27+
"allowedDomains": []string{"yourcompany.com"},
28+
"allowedOrigins": []string{"https://claude.ai"},
29+
"tokenTtl": "24h",
30+
"storage": "memory",
31+
"idp": map[string]any{
32+
"provider": "google",
33+
"clientId": map[string]string{"$env": "GOOGLE_CLIENT_ID"},
34+
"clientSecret": map[string]string{"$env": "GOOGLE_CLIENT_SECRET"},
35+
"redirectUri": "https://mcp.yourcompany.com/oauth/callback",
36+
},
37+
"jwtSecret": map[string]string{"$env": "JWT_SECRET"},
38+
"encryptionKey": map[string]string{"$env": "ENCRYPTION_KEY"},
3639
},
3740
},
3841
"mcpServers": map[string]any{
3942
"postgres": map[string]any{
4043
"transportType": "stdio",
4144
"command": "docker",
4245
"args": []any{
43-
"run", "--rm", "-i",
44-
"mcp/postgres:latest",
45-
map[string]string{"$env": "POSTGRES_URL"},
46+
"run", "--rm", "-i", "--network", "host",
47+
"-e", "POSTGRES_HOST",
48+
"-e", "POSTGRES_PORT",
49+
"-e", "POSTGRES_DATABASE",
50+
"-e", "POSTGRES_USER",
51+
"-e", "POSTGRES_PASSWORD",
52+
"us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:latest",
53+
"--stdio", "--prebuilt", "postgres",
54+
},
55+
"env": map[string]any{
56+
"POSTGRES_HOST": map[string]string{"$env": "POSTGRES_HOST"},
57+
"POSTGRES_PORT": map[string]string{"$env": "POSTGRES_PORT"},
58+
"POSTGRES_DATABASE": map[string]string{"$env": "POSTGRES_DATABASE"},
59+
"POSTGRES_USER": map[string]string{"$env": "POSTGRES_USER"},
60+
"POSTGRES_PASSWORD": map[string]string{"$env": "POSTGRES_PASSWORD"},
4661
},
4762
},
4863
},

config-admin-example.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@
77
"auth": {
88
"kind": "oauth",
99
"issuer": "https://mcp.example.com",
10+
"idp": {
11+
"provider": "google",
12+
"clientId": {"$env": "GOOGLE_CLIENT_ID"},
13+
"clientSecret": {"$env": "GOOGLE_CLIENT_SECRET"},
14+
"redirectUri": "https://mcp.example.com/oauth/callback"
15+
},
1016
"allowedDomains": ["example.com"],
1117
"allowedOrigins": ["https://claude.ai"],
1218
"tokenTtl": "1h",
1319
"storage": "memory",
14-
"googleClientId": {"$env": "GOOGLE_CLIENT_ID"},
15-
"googleClientSecret": {"$env": "GOOGLE_CLIENT_SECRET"},
16-
"googleRedirectUri": "https://mcp.example.com/oauth/callback",
1720
"jwtSecret": {"$env": "JWT_SECRET"},
1821
"encryptionKey": {"$env": "ENCRYPTION_KEY"}
1922
},

config-inline-example.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@
77
"auth": {
88
"kind": "oauth",
99
"issuer": "https://mcp.example.com",
10+
"idp": {
11+
"provider": "google",
12+
"clientId": {"$env": "GOOGLE_CLIENT_ID"},
13+
"clientSecret": {"$env": "GOOGLE_CLIENT_SECRET"},
14+
"redirectUri": "https://mcp.example.com/oauth/callback"
15+
},
1016
"allowedDomains": ["example.com"],
1117
"allowedOrigins": ["https://claude.ai"],
1218
"tokenTtl": "1h",
1319
"storage": "memory",
14-
"googleClientId": {"$env": "GOOGLE_CLIENT_ID"},
15-
"googleClientSecret": {"$env": "GOOGLE_CLIENT_SECRET"},
16-
"googleRedirectUri": "https://mcp.example.com/oauth/callback",
1720
"jwtSecret": {"$env": "JWT_SECRET"},
1821
"encryptionKey": {"$env": "ENCRYPTION_KEY"}
1922
}

config-inline-test.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@
77
"auth": {
88
"kind": "oauth",
99
"issuer": "http://localhost:8080",
10+
"idp": {
11+
"provider": "google",
12+
"clientId": {"$env": "GOOGLE_CLIENT_ID"},
13+
"clientSecret": {"$env": "GOOGLE_CLIENT_SECRET"},
14+
"redirectUri": "http://localhost:8080/oauth/callback"
15+
},
1016
"allowedDomains": ["gmail.com"],
1117
"allowedOrigins": ["https://claude.ai"],
1218
"tokenTtl": "1h",
1319
"storage": "memory",
14-
"googleClientId": {"$env": "GOOGLE_CLIENT_ID"},
15-
"googleClientSecret": {"$env": "GOOGLE_CLIENT_SECRET"},
16-
"googleRedirectUri": "http://localhost:8080/oauth/callback",
1720
"jwtSecret": {"$env": "JWT_SECRET"},
1821
"encryptionKey": {"$env": "ENCRYPTION_KEY"}
1922
}

config-oauth-firestore.example.json

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@
88
"kind": "oauth",
99
"issuer": {"$env": "OAUTH_ISSUER"},
1010
"gcpProject": {"$env": "GCP_PROJECT"},
11+
"idp": {
12+
"provider": "google",
13+
"clientId": {"$env": "GOOGLE_CLIENT_ID"},
14+
"clientSecret": {"$env": "GOOGLE_CLIENT_SECRET"},
15+
"redirectUri": {"$env": "GOOGLE_REDIRECT_URI"}
16+
},
1117
"allowedDomains": ["yourcompany.com", "contractors.yourcompany.com"],
1218
"allowedOrigins": ["https://claude.ai", "https://yourcompany.com"],
1319
"tokenTtl": "24h",
1420
"storage": "firestore",
15-
"googleClientId": {"$env": "GOOGLE_CLIENT_ID"},
16-
"googleClientSecret": {"$env": "GOOGLE_CLIENT_SECRET"},
17-
"googleRedirectUri": {"$env": "GOOGLE_REDIRECT_URI"},
1821
"jwtSecret": {"$env": "JWT_SECRET"},
1922
"encryptionKey": {"$env": "ENCRYPTION_KEY"}
2023
}
@@ -25,11 +28,20 @@
2528
"command": "docker",
2629
"args": [
2730
"run", "--rm", "-i", "--network", "host",
28-
"mcp/postgres",
29-
{"$env": "DATABASE_URL"}
31+
"-e", "POSTGRES_HOST",
32+
"-e", "POSTGRES_PORT",
33+
"-e", "POSTGRES_DATABASE",
34+
"-e", "POSTGRES_USER",
35+
"-e", "POSTGRES_PASSWORD",
36+
"us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:latest",
37+
"--stdio", "--prebuilt", "postgres"
3038
],
3139
"env": {
32-
"PGPASSWORD": {"$env": "POSTGRES_PASSWORD"}
40+
"POSTGRES_HOST": {"$env": "POSTGRES_HOST"},
41+
"POSTGRES_PORT": {"$env": "POSTGRES_PORT"},
42+
"POSTGRES_DATABASE": {"$env": "POSTGRES_DATABASE"},
43+
"POSTGRES_USER": {"$env": "POSTGRES_USER"},
44+
"POSTGRES_PASSWORD": {"$env": "POSTGRES_PASSWORD"}
3345
}
3446
},
3547
"notion": {

config-oauth.example.json

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@
88
"kind": "oauth",
99
"issuer": {"$env": "OAUTH_ISSUER"},
1010
"gcpProject": {"$env": "GCP_PROJECT"},
11+
"idp": {
12+
"provider": "google",
13+
"clientId": {"$env": "GOOGLE_CLIENT_ID"},
14+
"clientSecret": {"$env": "GOOGLE_CLIENT_SECRET"},
15+
"redirectUri": {"$env": "GOOGLE_REDIRECT_URI"}
16+
},
1117
"allowedDomains": ["yourcompany.com", "contractors.yourcompany.com"],
1218
"allowedOrigins": ["https://claude.ai", "https://yourcompany.com"],
1319
"tokenTtl": "24h",
1420
"storage": "memory",
15-
"googleClientId": {"$env": "GOOGLE_CLIENT_ID"},
16-
"googleClientSecret": {"$env": "GOOGLE_CLIENT_SECRET"},
17-
"googleRedirectUri": {"$env": "GOOGLE_REDIRECT_URI"},
1821
"jwtSecret": {"$env": "JWT_SECRET"},
1922
"encryptionKey": {"$env": "ENCRYPTION_KEY"}
2023
}
@@ -25,11 +28,20 @@
2528
"command": "docker",
2629
"args": [
2730
"run", "--rm", "-i", "--network", "host",
28-
"mcp/postgres",
29-
{"$env": "DATABASE_URL"}
31+
"-e", "POSTGRES_HOST",
32+
"-e", "POSTGRES_PORT",
33+
"-e", "POSTGRES_DATABASE",
34+
"-e", "POSTGRES_USER",
35+
"-e", "POSTGRES_PASSWORD",
36+
"us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:latest",
37+
"--stdio", "--prebuilt", "postgres"
3038
],
3139
"env": {
32-
"PGPASSWORD": {"$env": "POSTGRES_PASSWORD"}
40+
"POSTGRES_HOST": {"$env": "POSTGRES_HOST"},
41+
"POSTGRES_PORT": {"$env": "POSTGRES_PORT"},
42+
"POSTGRES_DATABASE": {"$env": "POSTGRES_DATABASE"},
43+
"POSTGRES_USER": {"$env": "POSTGRES_USER"},
44+
"POSTGRES_PASSWORD": {"$env": "POSTGRES_PASSWORD"}
3345
}
3446
},
3547
"notion": {

config-oauth.json

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,41 @@
88
"kind": "oauth",
99
"issuer": "https://mcp-internal.yourcompany.org",
1010
"gcpProject": {"$env": "GCP_PROJECT"},
11+
"idp": {
12+
"provider": "google",
13+
"clientId": {"$env": "GOOGLE_CLIENT_ID"},
14+
"clientSecret": {"$env": "GOOGLE_CLIENT_SECRET"},
15+
"redirectUri": "https://mcp-internal.yourcompany.org/oauth/callback"
16+
},
1117
"allowedDomains": ["yourcompany.com"],
1218
"allowedOrigins": ["https://claude.ai"],
1319
"tokenTtl": "24h",
1420
"storage": "memory",
15-
"googleClientId": {"$env": "GOOGLE_CLIENT_ID"},
16-
"googleClientSecret": {"$env": "GOOGLE_CLIENT_SECRET"},
17-
"googleRedirectUri": "https://mcp-internal.yourcompany.org/oauth/callback",
1821
"jwtSecret": {"$env": "JWT_SECRET"},
1922
"encryptionKey": {"$env": "ENCRYPTION_KEY"}
2023
}
2124
},
2225
"mcpServers": {
2326
"postgres": {
2427
"transportType": "stdio",
25-
"command": "docker",
28+
"command": "docker",
2629
"args": [
27-
"run", "--rm", "-i",
28-
"mcp/postgres:latest",
29-
"postgresql://user:password@localhost:5432/database"
30-
]
30+
"run", "--rm", "-i", "--network", "host",
31+
"-e", "POSTGRES_HOST",
32+
"-e", "POSTGRES_PORT",
33+
"-e", "POSTGRES_DATABASE",
34+
"-e", "POSTGRES_USER",
35+
"-e", "POSTGRES_PASSWORD",
36+
"us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:latest",
37+
"--stdio", "--prebuilt", "postgres"
38+
],
39+
"env": {
40+
"POSTGRES_HOST": {"$env": "POSTGRES_HOST"},
41+
"POSTGRES_PORT": {"$env": "POSTGRES_PORT"},
42+
"POSTGRES_DATABASE": {"$env": "POSTGRES_DATABASE"},
43+
"POSTGRES_USER": {"$env": "POSTGRES_USER"},
44+
"POSTGRES_PASSWORD": {"$env": "POSTGRES_PASSWORD"}
45+
}
3146
},
3247
"notion": {
3348
"transportType": "stdio",

config-token.example.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@
1111
"command": "docker",
1212
"args": [
1313
"run", "--rm", "-i", "--network", "host",
14-
"mcp/postgres",
15-
"postgresql://testuser:testpass@localhost:5432/testdb"
14+
"-e", "POSTGRES_HOST=localhost",
15+
"-e", "POSTGRES_PORT=5432",
16+
"-e", "POSTGRES_DATABASE=testdb",
17+
"-e", "POSTGRES_USER=testuser",
18+
"-e", "POSTGRES_PASSWORD=testpass",
19+
"us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:latest",
20+
"--stdio", "--prebuilt", "postgres"
1621
],
1722
"serviceAuths": [
1823
{

config-user-tokens-example.json

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@
88
"kind": "oauth",
99
"issuer": {"$env": "OAUTH_ISSUER"},
1010
"gcpProject": {"$env": "GCP_PROJECT"},
11+
"idp": {
12+
"provider": "google",
13+
"clientId": {"$env": "GOOGLE_CLIENT_ID"},
14+
"clientSecret": {"$env": "GOOGLE_CLIENT_SECRET"},
15+
"redirectUri": {"$env": "GOOGLE_REDIRECT_URI"}
16+
},
1117
"allowedDomains": ["yourcompany.com"],
1218
"allowedOrigins": ["https://claude.ai"],
1319
"tokenTtl": "24h",
1420
"storage": "memory",
15-
"googleClientId": {"$env": "GOOGLE_CLIENT_ID"},
16-
"googleClientSecret": {"$env": "GOOGLE_CLIENT_SECRET"},
17-
"googleRedirectUri": {"$env": "GOOGLE_REDIRECT_URI"},
1821
"jwtSecret": {"$env": "JWT_SECRET"},
1922
"encryptionKey": {"$env": "ENCRYPTION_KEY"}
2023
}
@@ -57,11 +60,20 @@
5760
"command": "docker",
5861
"args": [
5962
"run", "--rm", "-i", "--network", "host",
60-
"mcp/postgres",
61-
{"$env": "DATABASE_URL"}
63+
"-e", "POSTGRES_HOST",
64+
"-e", "POSTGRES_PORT",
65+
"-e", "POSTGRES_DATABASE",
66+
"-e", "POSTGRES_USER",
67+
"-e", "POSTGRES_PASSWORD",
68+
"us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:latest",
69+
"--stdio", "--prebuilt", "postgres"
6270
],
6371
"env": {
64-
"PGPASSWORD": {"$env": "POSTGRES_PASSWORD"}
72+
"POSTGRES_HOST": {"$env": "POSTGRES_HOST"},
73+
"POSTGRES_PORT": {"$env": "POSTGRES_PORT"},
74+
"POSTGRES_DATABASE": {"$env": "POSTGRES_DATABASE"},
75+
"POSTGRES_USER": {"$env": "POSTGRES_USER"},
76+
"POSTGRES_PASSWORD": {"$env": "POSTGRES_PASSWORD"}
6577
}
6678
}
6779
}

0 commit comments

Comments
 (0)