Authentication

Unfold CMS uses Laravel Fortify for authentication, providing a secure login system with two-factor authentication, social login, email verification, and rate limiting.

Login

Standard Login

Users log in with their email and password at /login. The login form includes:

  • Email field
  • Password field
  • "Remember Me" checkbox
  • Link to password reset

Rate Limiting

Login attempts are rate-limited to prevent brute force attacks:

Limit Rate
Login attempts 5 per minute
Password reset 3 per minute

After exceeding the limit, users must wait before trying again. The lockout duration is communicated through error messages.

Two-Factor Authentication (2FA)

Unfold CMS supports TOTP-based two-factor authentication powered by Laravel Fortify.

Enabling 2FA

  1. Navigate to Settings > Security in the user's profile
  2. Click Enable Two-Factor Authentication
  3. Scan the QR code with an authenticator app (Google Authenticator, Authy, etc.)
  4. Enter the verification code to confirm
  5. Save the recovery codes in a safe place

Login with 2FA

When 2FA is enabled:

  1. User enters email and password
  2. After successful credential check, a 2FA challenge is presented
  3. User enters the 6-digit code from their authenticator app
  4. Access is granted

Recovery Codes

During 2FA setup, recovery codes are generated. These can be used if the authenticator app is unavailable. Each recovery code can only be used once.

Users can regenerate recovery codes from their security settings.

Email Verification

New user accounts can require email verification before full access is granted.

Email verification can be toggled in Settings > Authentication in the admin panel.

Verification Flow

  1. User registers or is created with an unverified email
  2. A verification email is sent with a signed link
  3. User clicks the link to verify
  4. The email_verified_at timestamp is set

Unverified users can log in but may have restricted access depending on your middleware configuration.

Resending Verification

Users can request a new verification email from their profile or the verification notice page.

Password Reset

Reset Flow

  1. User clicks "Forgot Password?" on the login page
  2. Enters their email address
  3. Receives a password reset email with a signed, time-limited link
  4. Clicks the link and enters a new password
  5. Password is updated and user can log in

Password reset links expire after 60 minutes.

Password Change

Authenticated users can change their password from Settings > Password. They must provide their current password to confirm the change.

When a password is changed, a password_changed notification is sent (if notifications are enabled).

Social Login

Pro Feature — Social login is available in the Pro and Agency tiers.

Unfold CMS supports OAuth-based social login through Laravel Socialite. Visitors can sign in with one click instead of creating an email/password account.

Supported Providers

Google, GitHub, and Facebook are supported. Enable providers and enter their credentials in Settings > Authentication > Social Login in the admin panel.

Callback URL Pattern

Every provider needs the same callback URL pattern:

https://yourdomain.com/auth/{provider}/callback

So Google's callback is /auth/google/callback, GitHub's is /auth/github/callback, Facebook's is /auth/facebook/callback.

Setup — Google

  1. Go to Google Cloud Console → pick or create a project
  2. Open APIs & Services → OAuth consent screen and fill it in (External user type, app name, support email, authorized domain). You don't need to publish it for testing.
  3. Open APIs & Services → Credentials → + Create Credentials → OAuth Client ID
  4. Application type: Web application
  5. Authorized JavaScript origins: https://yourdomain.com
  6. Authorized redirect URIs: https://yourdomain.com/auth/google/callback
  7. Click Create — copy the Client ID (xxxxx.apps.googleusercontent.com) and Client Secret (GOCSPX-xxxxx)
  8. In the CMS admin: /admin/settingsAuthentication tab → toggle Enable Social Login ON → toggle Enable Google Login ON → paste Client ID + Secret → Save

Setup — GitHub

GitHub is the easiest of the three.

  1. Go to GitHub Developer SettingsOAuth Apps → New OAuth App
  2. Application name: your site name
  3. Homepage URL: https://yourdomain.com
  4. Authorization callback URL: https://yourdomain.com/auth/github/callback
  5. Click Register application. Copy the Client ID, then click Generate a new client secret and copy that (you only see it once).
  6. In the CMS admin: /admin/settingsAuthentication tab → make sure Enable Social Login is ON → toggle Enable GitHub Login ON → paste Client ID + Secret → Save

Setup — Facebook

Facebook is the most involved, but basic email + profile login works without app review.

  1. Go to Facebook for DevelopersCreate App
  2. Use case: Authenticate and request data from users → type: Consumer
  3. Fill in app name + contact email → Create
  4. On the app dashboard, find Facebook Login → Set up → pick Web platform
  5. Site URL: https://yourdomain.com. Skip the quickstart.
  6. Go to Facebook Login → Settings in the left sidebar
  7. Valid OAuth Redirect URIs: https://yourdomain.com/auth/facebook/callback
  8. Save Changes
  9. Go to Settings → Basic → copy the App ID (this is your Client ID) → click Show next to App Secret and copy it
  10. While you're on Settings → Basic, also fill in App Domains: yourdomain.com and your Privacy Policy URL (Facebook requires one) → Save Changes
  11. Flip the App Mode switch from Development to Live (top of the dashboard)
  12. In the CMS admin: /admin/settingsAuthentication tab → make sure Enable Social Login is ON → toggle Enable Facebook Login ON → paste App ID + App Secret → Save

Social Login Flow

  1. User clicks "Continue with Google" (or other provider)
  2. Redirected to the provider's OAuth consent screen
  3. User grants permission
  4. Redirected back to the CMS
  5. If the email matches an existing account, the provider is linked to that account and they're logged in
  6. If no match, a new account is created with the User role, email_verified_at set (the provider already verified the email), and provider / provider_id / provider_avatar populated

Verifying It Works

After saving credentials:

  1. Open an incognito window (you may still be logged in on your normal browser)
  2. Go to https://yourdomain.com/login
  3. The "Continue with Google" (or GitHub / Facebook) button should appear below the email/password form
  4. Click it → approve on the provider's screen → you should land back on your site signed in
  5. Check /admin/users — the new row should have your email and the provider column should say google / github / facebook

Common Issues

Button doesn't appear on /login — the master toggle Enable Social Login is off, or the provider-specific toggle is off.

"Invalid redirect URI" on the provider's screen — the URL in their console doesn't match https://yourdomain.com/auth/{provider}/callback exactly, including https:// vs http:// and trailing slashes.

Google shows "This app isn't verified" — normal for new apps. Click Advanced → Go to (your app). To remove the warning permanently, submit your app for Google's verification process (free, takes a few days, only needed at production scale).

Facebook says app is in development mode — flip the App Mode toggle to Live (Step 11 above).

GitHub returns "Bad credentials" — the Client Secret was regenerated after you saved it. Generate a fresh secret on GitHub, paste it into UnfoldCMS, save.

User already exists with that email — the provider is linked to the existing account; no duplicate is created. They can use either method going forward.

Invalid Provider Handling

If a user tries to authenticate with an unconfigured provider, they're redirected back with an error message.

Registration

Registration can be enabled or disabled in Settings > Authentication in the admin panel.

Registration Flow

  1. User visits /register
  2. Fills in name, email, and password
  3. Account is created with the User role
  4. Verification email is sent (if enabled)
  5. Welcome email is sent (if enabled)

Session Security

Feature Description
CSRF Protection All forms include CSRF tokens
Session Encryption Sessions are encrypted by default
Secure Cookies Cookies use HttpOnly and Secure flags in production
Session Timeout Sessions expire after the configured lifetime

Rate Limits

All authentication endpoints are rate-limited:

Endpoint Limit
Login 5 per minute
Password Reset 3 per minute
Registration 5 per minute
Email Verification 5 per minute

Auth Page Appearance

Templates can customize the look of authentication pages (login, register, forgot password, etc.) through settings in the admin panel at Settings > Template > Auth Pages.

Layouts

Three layout options are available:

Layout Description
simple Centered form on a clean background (default)
card Form inside a card component
split Two-column layout with branding on one side and form on the other

Branding Settings

These settings apply to all auth page layouts, but are most visible in the split layout:

Setting Description Default
Branding Title Large heading on the branding panel "Unfold your story"
Branding Description Subtext below the title "The modern content management system..."
Background Image Image for the branding panel (URL or media path) None
Background Color Gradient start color (used when no image) #2563EB
Background Color End Gradient end color #1D4ED8

How It Works

Auth page appearance is controlled per-template. Settings are stored with the key pattern:

template.{template_name}.auth.layout
template.{template_name}.auth.branding_title
template.{template_name}.auth.branding_description
template.{template_name}.auth.background_image
template.{template_name}.auth.background_color
template.{template_name}.auth.background_color_end

The active template's auth settings are automatically passed to all auth pages via the authAppearance shared prop in the Inertia middleware.

For Template Developers

Auth pages use the AuthLayout component (layouts/auth-layout.tsx) which automatically selects the correct layout based on the template's settings. Your auth pages should wrap their content with this component:

import AuthLayout from '@/layouts/auth-layout';

export default function Login() {
    return (
        <AuthLayout title="Sign in" description="Enter your credentials">
            {/* Form fields */}
        </AuthLayout>
    );
}

The AuthLayout component reads authAppearance from page props and renders the appropriate layout (AuthSimpleLayout, AuthCardLayout, or AuthSplitLayout).