Authentication, social login, and team invites in Laravel SaaS: the complete guide
How to build a complete auth system for Laravel SaaS products, covering registration, social login with Google and GitHub, email verification, team invitations, and role-based workspace access.
Quick Answer
Quick answer: Authentication, social login, and team invites in Laravel SaaS: the complete guide
How to build a complete auth system for Laravel SaaS products, covering registration, social login with Google and GitHub, email verification, team invitations, and role-based workspace access.
See supporting documentationAuthentication, social login, and team invites in Laravel SaaS: the complete guide
Authentication in a SaaS application is not just login and logout. It is the entire chain from first visit to active team member: registration, email verification, social login, workspace creation, team invitations, and role-based access control.
Getting this right early prevents painful retrofits later. This guide walks through how to architect a complete auth system for a Laravel SaaS product.
Why SaaS auth is different from regular app auth
A traditional web app usually has one account model: user registers, user logs in, user uses the app.
SaaS products add layers:
| Concern | Traditional app | SaaS product |
|---|---|---|
| Account unit | Individual user | User belongs to one or more workspaces |
| Onboarding | Register and use | Register, create workspace, invite team |
| Authorization | Global roles (admin/user) | Workspace-scoped roles (owner/admin/member) |
| Login options | Email/password | Email/password + social providers |
| Billing context | Per user | Per workspace, often per seat |
| Session context | Single context | Workspace-aware context switching |
Building auth as if you are building a single-user app and then adding workspace context later is one of the most expensive refactors in SaaS development.
Part 1: Registration and email verification
Registration flow architecture
A clean SaaS registration flow does more than create a user record:
- Validate input (email uniqueness, password strength)
- Create user record
- Create default workspace for the user
- Attach user to workspace as owner
- Send verification email
- Redirect to onboarding (not directly to dashboard)
Why workspace creation happens at registration
If you wait for users to manually create their first workspace, you introduce an empty state that confuses onboarding. Creating a default workspace during registration means the user immediately has context.
// Inside your registration action/service
$user = User::create([
'name' => $validated['name'],
'email' => $validated['email'],
'password' => Hash::make($validated['password']),
]);
$workspace = Workspace::create([
'name' => $user->name . "'s Workspace",
'owner_id' => $user->id,
]);
$workspace->members()->attach($user->id, ['role' => 'owner']);
$user->update(['current_workspace_id' => $workspace->id]);Email verification
Laravel ships with email verification via the MustVerifyEmail interface. For SaaS, enforce verification before allowing access to billing or team features, not necessarily before the user can see the dashboard.
This gives users a quick first experience while still ensuring verified emails before critical actions.
Part 2: Social login with Google and GitHub
Why social login matters for SaaS
Social login reduces registration friction. For developer-facing SaaS products, GitHub login is especially effective because the audience already has accounts and trusts the provider.
Conversion impact:
- Fewer abandoned registrations (no password creation step)
- Higher trust signal from recognized OAuth providers
- Reduced password reset support volume
Implementation with Laravel Socialite
Laravel Socialite handles the OAuth flow. The key architectural decision is how to reconcile social accounts with email/password accounts.
Account linking strategy
When a user signs in with Google or GitHub, you need to handle three cases:
| Scenario | What to do |
|---|---|
| New email, no existing account | Create user + default workspace |
| Email matches existing account, first social login | Link social identity to existing user |
| Email matches existing account, social already linked | Log in directly |
public function handleProviderCallback(string $provider)
{
$socialUser = Socialite::driver($provider)->user();
$user = User::where('email', $socialUser->getEmail())->first();
if (!$user) {
$user = $this->createUserWithWorkspace($socialUser, $provider);
}
$this->linkSocialIdentity($user, $socialUser, $provider);
Auth::login($user, remember: true);
return redirect()->intended('/dashboard');
}Storing social identities
Use a separate social_accounts table rather than putting provider columns on the users table. This supports multiple providers per user cleanly:
Schema::create('social_accounts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->string('provider');
$table->string('provider_id');
$table->string('provider_token')->nullable();
$table->string('provider_refresh_token')->nullable();
$table->timestamps();
$table->unique(['provider', 'provider_id']);
});Security considerations
- Always verify the email from the OAuth provider is verified before trusting it.
- Do not allow social login to bypass email verification for existing accounts.
- Store tokens encrypted if you need them for API access later.
Part 3: Two-factor authentication
For SaaS products handling billing or sensitive business data, two-factor authentication (2FA) should be available even if not enforced by default.
Implementation approach
- Use TOTP (Time-based One-Time Password) with apps like Google Authenticator or Authy.
- Store the 2FA secret encrypted in the users table.
- Generate recovery codes during setup so users are not locked out.
- Check 2FA status during the login flow, after password validation but before session creation.
When to enforce 2FA
- Optional for all users (recommended default).
- Required for workspace owners and admins (good middle ground).
- Required for all users (enterprise-tier feature, common in B2B SaaS).
Part 4: Team invitations
Team invitations are where SaaS auth diverges most from traditional applications.
Invitation flow architecture
- Workspace admin sends invite with email and role.
- System creates invitation record with unique token and expiration.
- Invite email sent with accept link.
- Recipient clicks link and either registers or logs in.
- System validates token, attaches user to workspace with specified role.
- Invitation marked as accepted.
Invitation data model
Schema::create('workspace_invitations', function (Blueprint $table) {
$table->id();
$table->foreignId('workspace_id')->constrained()->cascadeOnDelete();
$table->foreignId('invited_by')->constrained('users')->cascadeOnDelete();
$table->string('email');
$table->string('role')->default('member');
$table->string('token')->unique();
$table->timestamp('expires_at');
$table->timestamp('accepted_at')->nullable();
$table->timestamps();
$table->unique(['workspace_id', 'email']);
});Handling the accept flow
The invitation accept logic needs to handle two paths:
Path A: Recipient already has an account
public function accept(string $token)
{
$invitation = WorkspaceInvitation::where('token', $token)
->whereNull('accepted_at')
->where('expires_at', '>', now())
->firstOrFail();
$user = Auth::user() ?? User::where('email', $invitation->email)->first();
if (!$user) {
return redirect()->route('register', ['invitation' => $token]);
}
$invitation->workspace->members()->attach($user->id, [
'role' => $invitation->role,
]);
$invitation->update(['accepted_at' => now()]);
return redirect('/dashboard');
}Path B: Recipient needs to register
After registration, check for pending invitations matching the new user's email and auto-accept them.
Rate limiting invitations
Prevent invitation abuse by limiting sends per workspace per hour. This protects against both spam and accidental bulk invites.
Part 5: Role-based access in workspaces
Role model design
Keep roles simple and workspace-scoped:
| Role | Capabilities |
|---|---|
| Owner | Full control, billing, delete workspace |
| Admin | Manage members, manage resources |
| Member | Use workspace resources, no admin actions |
Store the role on the workspace_user pivot table, not on the user record. A user can be an owner of one workspace and a member of another.
Authorization with Laravel policies
Use policies that receive the workspace context:
class ProjectPolicy
{
public function update(User $user, Project $project): bool
{
$membership = $project->workspace->members()
->where('user_id', $user->id)
->first();
if (!$membership) {
return false;
}
return in_array($membership->pivot->role, ['owner', 'admin'])
|| $project->user_id === $user->id;
}
}Middleware for workspace context
Set the active workspace early in the request lifecycle so controllers and policies can reference it without repeated lookups:
class SetWorkspaceContext
{
public function handle(Request $request, Closure $next)
{
$user = $request->user();
$workspace = $user->currentWorkspace;
if (!$workspace || !$workspace->members->contains($user)) {
abort(403, 'No active workspace.');
}
app()->instance('currentWorkspace', $workspace);
return $next($request);
}
}Part 6: Session management for multi-workspace users
Users who belong to multiple workspaces need context switching without logging out.
Workspace switching
Store the active workspace ID on the user record (current_workspace_id). Switching workspaces updates this value and redirects to the dashboard.
Session security
- Invalidate sessions on password change.
- Allow users to view and revoke active sessions from other devices.
- Set reasonable session lifetimes (shorter for billing pages if needed).
How these pieces connect in a SaaS product
The full auth lifecycle for a SaaS user:
- User discovers product and registers (email/password or social).
- Default workspace is created automatically.
- User verifies email.
- User configures workspace and invites teammates.
- Teammates accept invitations and join with assigned roles.
- Workspace owner sets up billing (tied to workspace, not user).
- Members collaborate within workspace-scoped authorization.
- Users can create or join additional workspaces.
Every step in this chain needs to work reliably before you ship to customers.
Common auth mistakes in Laravel SaaS apps
- No workspace creation at registration. Users land on an empty dashboard with no context.
- Social login creates duplicate accounts. Missing email-based account linking causes separate accounts for the same person.
- Roles stored on the user model. This breaks when users belong to multiple workspaces with different roles.
- Invitation tokens that never expire. Stale invitations become a security risk.
- No 2FA option. Enterprise buyers often require it before evaluating your product.
Start with the auth foundation already built
Implementing this full auth stack (registration, social login, verification, invitations, roles, workspace context) from scratch takes significant engineering time and testing effort.
If you want to skip the auth infrastructure work and start building product features, SaasForgeKit provides this entire auth system out of the box, including Google and GitHub social login, workspace-scoped roles, team invitations, and session management.
Ready to ship faster?
Build your SaaS with a production-ready foundation
Launch with authentication, billing, tenancy, and team workflows already in place, then focus on the features that make your product unique.
Related posts
How to deploy a Laravel SaaS to production with zero downtime (2026 guide)
A practical guide to deploying Laravel SaaS applications with zero downtime, covering migration strategies, queue workers, health checks, and multi-tenant considerations.
SaasForgeKit vs Laravel Spark vs Wave (2026): which starter kit should you choose?
A practical 2026 decision guide comparing SaasForgeKit, Laravel Spark, and Wave for teams choosing a Laravel SaaS foundation.
Laravel tenancy architecture decision framework for SaaS founders (2026)
A clear decision framework for choosing single-database vs multi-database tenancy in Laravel SaaS products, including migration triggers and tradeoffs.