Access Rules
Beta
This feature is in beta. Core behavior is stable, but some APIs or configuration may change before general availability.
Authentication also has its own access-rule surface.
Use auth.access to allow or deny specific authentication actions such as sign-up, sign-in, password reset, MFA verification, profile reads, session reads, OAuth redirects, refresh, and sign-out.
This is different from database, storage, database subscription, room, or push access rules:
- Authentication access rules protect auth endpoints and auth actions
- Other access rules protect product resources such as rows, files, channels, rooms, and notifications
Configuration
import { defineConfig } from '@edgebase/shared';
export default defineConfig({
auth: {
access: {
signUp(input, ctx) {
const email = String(input?.email ?? '');
return email.endsWith('@company.com');
},
signIn(_input, ctx) {
return ctx.ip !== '203.0.113.10';
},
refresh(_input, ctx) {
return ctx.auth !== null;
},
mfaTotpEnroll(_input, ctx) {
return ctx.auth?.custom?.plan === 'pro';
},
},
},
});
If a rule returns false, the server rejects the request with 403 Forbidden.
Signature
type AuthAccessRule = (
input: Record<string, unknown> | null,
ctx: {
request?: Request;
auth?: AuthContext | null;
ip?: string;
},
) => boolean | Promise<boolean>;
What You Can Check
input- Request payload for the current auth action
ctx.auth- Current authenticated user if one exists
ctx.ip- Client IP address
ctx.request- Raw request object
Supported Actions
| Action | Purpose |
|---|---|
signUp | Email/password sign-up |
signIn | Email/password sign-in |
signInAnonymous | Anonymous sign-in |
signInMagicLink | Request a magic link |
verifyMagicLink | Complete magic link sign-in |
signInPhone | Request phone OTP |
verifyPhoneOtp | Complete phone OTP sign-in |
linkPhone | Start phone linking |
verifyLinkPhone | Complete phone linking |
signInEmailOtp | Request email OTP |
verifyEmailOtp | Complete email OTP sign-in |
mfaTotpEnroll | Start TOTP enrollment |
mfaTotpVerify | Confirm TOTP enrollment |
mfaVerify | Complete MFA challenge |
mfaRecovery | Complete MFA via recovery code |
mfaTotpDelete | Disable TOTP |
mfaFactors | List MFA factors |
requestPasswordReset | Request password reset |
resetPassword | Complete password reset |
verifyEmail | Verify email |
changePassword | Change password |
changeEmail | Start email change |
verifyEmailChange | Complete email change |
passkeysRegisterOptions | Start passkey registration |
passkeysRegister | Complete passkey registration |
passkeysAuthOptions | Start passkey sign-in |
passkeysAuthenticate | Complete passkey sign-in |
passkeysList | List passkeys |
passkeysDelete | Delete a passkey |
getMe | Read current user profile |
updateProfile | Update current user profile |
getSessions | List current user sessions |
deleteSession | Revoke one session |
getIdentities | List linked identities |
deleteIdentity | Remove a linked identity |
linkEmail | Link email/password to an account |
oauthRedirect | Start OAuth sign-in |
oauthCallback | Complete OAuth sign-in |
oauthLinkStart | Start OAuth linking |
oauthLinkCallback | Complete OAuth linking |
refresh | Refresh JWT session |
signOut | Sign out |
Examples
Restrict Sign-Up Email Domains
auth: {
access: {
signUp(input) {
const email = String(input?.email ?? '');
return email.endsWith('@company.com');
},
},
}
Block Anonymous Sign-In By IP
auth: {
access: {
signInAnonymous(_input, ctx) {
return ctx.ip !== '203.0.113.10';
},
},
}
Require An Authenticated User For Profile Actions
auth: {
access: {
getMe(_input, ctx) {
return ctx.auth !== null;
},
updateProfile(_input, ctx) {
return ctx.auth !== null;
},
getSessions(_input, ctx) {
return ctx.auth !== null;
},
signOut(_input, ctx) {
return ctx.auth !== null;
},
},
}
Gate MFA Enrollment By Plan
auth: {
access: {
mfaTotpEnroll(_input, ctx) {
return ctx.auth?.custom?.plan === 'pro';
},
},
}
Default Behavior
- If a specific
auth.access.*rule is not defined, that action is not blocked byauth.access. - Built-in authentication requirements still apply:
- session-protected routes still require a valid token
- disabled users are still rejected
- captcha, MFA, password policy, and provider configuration still apply
In other words, auth.access is an extra policy layer, not a replacement for the built-in auth flow checks.