Skip to content

Commit 915877b

Browse files
authored
feat: limit oidc domains (#263)
1 parent bb8f3de commit 915877b

File tree

6 files changed

+37
-2
lines changed

6 files changed

+37
-2
lines changed

.env.example

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ TRELLO_APP_SECRET=
4343

4444
# OAuth providers (optional)
4545
BETTER_AUTH_TRUSTED_ORIGINS=
46+
# Optional: Restrict OIDC/Social sign-ins to specific email domains (comma-separated)
47+
BETTER_AUTH_ALLOWED_DOMAINS=
4648
GOOGLE_CLIENT_ID=
4749
GOOGLE_CLIENT_SECRET=
4850
DISCORD_CLIENT_ID=
@@ -80,4 +82,3 @@ TWITCH_CLIENT_SECRET=
8082
APPLE_CLIENT_ID=
8183
APPLE_CLIENT_SECRET=
8284
APPLE_APP_BUNDLE_IDENTIFIER=
83-

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ pnpm dev
150150
| `SMTP_REJECT_UNAUTHORIZED` | Reject invalid certificates (defaults to true if not set) | For Email | `false` |
151151
| `NEXT_PUBLIC_DISABLE_EMAIL` | To disable all email features | For Email | `true` |
152152
| `NEXT_PUBLIC_BASE_URL` | Base URL of your installation | Yes | `http://localhost:3000` |
153+
| `BETTER_AUTH_ALLOWED_DOMAINS` | Comma-separated list of allowed domains for OIDC logins | For OIDC/Social login | `example.com,subsidiary.com` |
153154
| `BETTER_AUTH_SECRET` | Auth encryption secret | Yes | Random 32+ char string |
154155
| `BETTER_AUTH_TRUSTED_ORIGINS` | Allowed callback origins | No | `http://localhost:3000,http://localhost:3001` |
155156
| `GOOGLE_CLIENT_ID` | Google OAuth client ID | For Google login | `xxx.apps.googleusercontent.com` |

cloud/docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ services:
6565
- BETTER_AUTH_TRUSTED_ORIGINS=${BETTER_AUTH_TRUSTED_ORIGINS}
6666
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
6767
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
68+
- BETTER_AUTH_ALLOWED_DOMAINS=${BETTER_AUTH_ALLOWED_DOMAINS}
6869

6970
# Analytics
7071
- NEXT_PUBLIC_UMAMI_ID=${NEXT_PUBLIC_UMAMI_ID}

docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ services:
6060
- BETTER_AUTH_TRUSTED_ORIGINS=${BETTER_AUTH_TRUSTED_ORIGINS}
6161
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
6262
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
63+
- BETTER_AUTH_ALLOWED_DOMAINS=${BETTER_AUTH_ALLOWED_DOMAINS}
6364
- DISCORD_CLIENT_ID=${DISCORD_CLIENT_ID}
6465
- DISCORD_CLIENT_SECRET=${DISCORD_CLIENT_SECRET}
6566
- GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID}

packages/auth/src/auth.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ export const configuredProviders = socialProviderList.reduce<
3232
requireSelectAccount?: boolean;
3333
clientKey?: string;
3434
issuer?: string;
35+
// Google-specific optional hints
36+
hostedDomain?: string;
37+
hd?: string;
3538
}
3639
>
3740
>((acc, provider) => {
@@ -69,6 +72,22 @@ export const configuredProviders = socialProviderList.reduce<
6972
acc[provider].tenantId = "common";
7073
acc[provider].requireSelectAccount = true;
7174
}
75+
// Add Google domain hint if allowed domains is configured
76+
if (
77+
provider === "google" &&
78+
Object.keys(acc).includes("google") &&
79+
acc[provider]
80+
) {
81+
const allowed = process.env.BETTER_AUTH_ALLOWED_DOMAINS
82+
?.split(",")
83+
.map((d) => d.trim().toLowerCase())
84+
.filter(Boolean);
85+
if (allowed && allowed.length > 0) {
86+
// Use the first domain as an authorization hint
87+
acc[provider].hostedDomain = allowed[0];
88+
acc[provider].hd = allowed[0];
89+
}
90+
}
7291
if (
7392
provider === "tiktok" &&
7493
Object.keys(acc).includes("tiktok") &&
@@ -343,7 +362,18 @@ export const initAuth = (db: dbClient) => {
343362
return Promise.resolve(false);
344363
}
345364

346-
return Promise.resolve(true);
365+
// Fall through to any additional checks below
366+
}
367+
// Enforce allowed domains (OIDC/social) if configured
368+
const allowed = process.env.BETTER_AUTH_ALLOWED_DOMAINS
369+
?.split(",")
370+
.map((d) => d.trim().toLowerCase())
371+
.filter(Boolean);
372+
if (allowed && allowed.length > 0) {
373+
const domain = user.email.split("@")[1]?.toLowerCase();
374+
if (!domain || !allowed.includes(domain)) {
375+
return Promise.resolve(false);
376+
}
347377
}
348378
return Promise.resolve(true);
349379
},

turbo.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"TRELLO_APP_SECRET",
5252
"GOOGLE_CLIENT_ID",
5353
"GOOGLE_CLIENT_SECRET",
54+
"BETTER_AUTH_ALLOWED_DOMAINS",
5455
"DISCORD_CLIENT_ID",
5556
"DISCORD_CLIENT_SECRET",
5657
"GITHUB_CLIENT_ID",

0 commit comments

Comments
 (0)