MojoAuth + Netlify Integration
Deploy MojoAuth passwordless authentication to your Netlify-hosted sites using our official one-click template. This integration provides a complete authentication solution for JAMstack applications with zero backend configuration.
- Deployment Type: One-click Netlify template
- Authentication Flow: OAuth 2.0 / OpenID Connect
- Hosting: Netlify Functions + Static Site
- Best For: JAMstack sites, static generators, serverless apps
Why Use MojoAuth with Netlify?
- One-Click Deployment: Deploy complete auth infrastructure in seconds
- Serverless Functions: Built-in Netlify Functions handle OAuth flow
- JAMstack Optimized: Perfect for static sites and modern web apps
- Zero Backend: No server management required
- Automatic SSL: Netlify provides HTTPS out of the box
- Git-Based Workflow: Deploy from GitHub with automatic updates
References
- GitHub Template: https://github.com/MojoAuth/mojoauth-netlify-template (opens in a new tab)
- Netlify Marketplace: Available as a one-click template
- MojoAuth Hosted Login: https://docs.mojoauth.com/hosted-login-page/ (opens in a new tab)
- Netlify Functions Docs: https://docs.netlify.com/functions/overview/ (opens in a new tab)
Prerequisites
- Netlify account (free tier works)
- GitHub account for repository deployment
- MojoAuth account with an OIDC application configured
- MojoAuth credentials:
- Client ID
- Client Secret
- Issuer:
https://api.mojoauth.com
Quick Start: One-Click Deployment
Option 1: Deploy from Netlify Marketplace
- Visit the Netlify Template Marketplace (opens in a new tab)
- Search for "MojoAuth"
- Click "Deploy to Netlify"
- Connect your GitHub account
- Configure environment variables (see below)
- Click "Save & Deploy"
Option 2: Deploy from GitHub
- Visit the template repository: https://github.com/MojoAuth/mojoauth-netlify-template (opens in a new tab)
- Click the "Deploy to Netlify" button
- Authorize Netlify to access your GitHub account
- Choose a repository name
- Configure environment variables
- Deploy!
Configuration
Step 1: Set Environment Variables
During deployment, configure these environment variables in Netlify:
# MojoAuth Configuration
MOJOAUTH_CLIENT_ID=your-client-id
MOJOAUTH_CLIENT_SECRET=your-client-secret
MOJOAUTH_ISSUER=https://api.mojoauth.com
MOJOAUTH_REDIRECT_URI=https://your-site.netlify.app/.netlify/functions/callback
# Application Configuration
BASE_URL=https://your-site.netlify.app
SESSION_SECRET=your-random-secret-key-hereTo add environment variables in Netlify:
- Go to your site in Netlify Dashboard
- Navigate to Site settings → Environment variables
- Click Add a variable
- Add each variable listed above
Step 2: Configure MojoAuth Dashboard
In your MojoAuth Dashboard → OIDC Application settings:
-
Allowed Callback URLs:
https://your-site.netlify.app/.netlify/functions/callbackhttp://localhost:8888/.netlify/functions/callback(for local testing)
-
Allowed Logout URLs:
https://your-site.netlify.app/http://localhost:8888/
-
Allowed Origins (CORS):
https://your-site.netlify.apphttp://localhost:8888
-
Scopes:
openid profile email
How It Works
The MojoAuth Netlify template includes:
1. Netlify Functions (Serverless)
/.netlify/functions/auth-login.js
// Initiates OAuth flow and redirects to MojoAuth
exports.handler = async (event, context) => {
const authUrl = `https://api.mojoauth.com/oauth/authorize?` +
`client_id=${process.env.MOJOAUTH_CLIENT_ID}&` +
`redirect_uri=${process.env.MOJOAUTH_REDIRECT_URI}&` +
`response_type=code&` +
`scope=openid profile email`;
return {
statusCode: 302,
headers: { Location: authUrl }
};
};/.netlify/functions/callback.js
// Handles OAuth callback and exchanges code for tokens
const axios = require('axios');
exports.handler = async (event, context) => {
const { code } = event.queryStringParameters;
// Exchange authorization code for tokens
const tokenResponse = await axios.post('https://api.mojoauth.com/oauth/token', {
grant_type: 'authorization_code',
code: code,
client_id: process.env.MOJOAUTH_CLIENT_ID,
client_secret: process.env.MOJOAUTH_CLIENT_SECRET,
redirect_uri: process.env.MOJOAUTH_REDIRECT_URI
});
const { access_token, id_token } = tokenResponse.data;
// Get user profile
const userResponse = await axios.get('https://api.mojoauth.com/oauth/userinfo', {
headers: { Authorization: `Bearer ${access_token}` }
});
// Set secure cookie and redirect
return {
statusCode: 302,
headers: {
Location: '/',
'Set-Cookie': `mojoauth_user=${JSON.stringify(userResponse.data)}; HttpOnly; Secure; SameSite=Lax; Path=/`
}
};
};/.netlify/functions/logout.js
// Clears session and logs out user
exports.handler = async (event, context) => {
return {
statusCode: 302,
headers: {
Location: '/',
'Set-Cookie': 'mojoauth_user=; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=0'
}
};
};2. Frontend Integration
Login Button (index.html):
<a href="/.netlify/functions/auth-login" class="login-btn">
Login with MojoAuth
</a>Display User Info:
<div id="user-profile" style="display:none;">
<img id="avatar" src="" alt="User Avatar">
<span id="username"></span>
<a href="/.netlify/functions/logout">Logout</a>
</div>
<script>
// Check if user is logged in
const user = getCookie('mojoauth_user');
if (user) {
const userData = JSON.parse(user);
document.getElementById('user-profile').style.display = 'block';
document.getElementById('username').textContent = userData.name;
document.getElementById('avatar').src = userData.picture || '/default-avatar.png';
}
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}
</script>Local Development
1. Clone Your Repository
git clone https://github.com/your-username/your-mojoauth-netlify-site.git
cd your-mojoauth-netlify-site2. Install Dependencies
npm install3. Set Up Local Environment
Create a .env file:
MOJOAUTH_CLIENT_ID=your-client-id
MOJOAUTH_CLIENT_SECRET=your-client-secret
MOJOAUTH_ISSUER=https://api.mojoauth.com
MOJOAUTH_REDIRECT_URI=http://localhost:8888/.netlify/functions/callback
BASE_URL=http://localhost:8888
SESSION_SECRET=local-development-secret4. Run Netlify Dev
netlify devThis starts a local server at http://localhost:8888 with Netlify Functions support.
5. Test Authentication
- Open
http://localhost:8888 - Click "Login with MojoAuth"
- Complete authentication on MojoAuth Hosted Login Page
- You'll be redirected back and logged in
Customization
Update Site Design
Edit index.html to match your brand:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My App - Powered by MojoAuth</title>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<nav>
<div class="logo">My App</div>
<div id="auth-section">
<!-- Auth buttons inserted by JavaScript -->
</div>
</nav>
<main>
<h1>Welcome to My Application</h1>
<p>Secure passwordless authentication powered by MojoAuth</p>
</main>
<script src="/app.js"></script>
</body>
</html>Add Protected Routes
Create a middleware function to protect certain pages:
/.netlify/functions/protected.js:
exports.handler = async (event, context) => {
const cookies = event.headers.cookie || '';
const userCookie = cookies.split(';').find(c => c.trim().startsWith('mojoauth_user='));
if (!userCookie) {
return {
statusCode: 401,
body: JSON.stringify({ error: 'Unauthorized' })
};
}
// User is authenticated, proceed
return {
statusCode: 200,
body: JSON.stringify({ message: 'Protected content', user: JSON.parse(userCookie.split('=')[1]) })
};
};Add User Profile Page
Create profile.html:
<!DOCTYPE html>
<html>
<head>
<title>My Profile</title>
</head>
<body>
<h1>User Profile</h1>
<div id="profile-data"></div>
<script>
async function loadProfile() {
const response = await fetch('/.netlify/functions/protected');
if (response.ok) {
const data = await response.json();
document.getElementById('profile-data').innerHTML = `
<p><strong>Name:</strong> ${data.user.name}</p>
<p><strong>Email:</strong> ${data.user.email}</p>
<p><strong>User ID:</strong> ${data.user.sub}</p>
`;
} else {
window.location.href = '/';
}
}
loadProfile();
</script>
</body>
</html>Deployment Workflow
Automatic Deployments
Once set up, Netlify automatically deploys on every push to your repository:
# Make changes locally
git add .
git commit -m "Update authentication flow"
git push origin main
# Netlify automatically rebuilds and deploysDeploy Previews
Netlify creates deploy previews for pull requests:
- Create a new branch
- Make changes and push
- Open a pull request
- Netlify generates a preview URL
- Test before merging
Manual Deploys
Trigger manual deploys from the Netlify Dashboard:
- Go to Deploys tab
- Click Trigger deploy → Deploy site
Advanced Configuration
Custom Domain
- In Netlify Dashboard → Domain settings
- Click Add custom domain
- Follow DNS configuration instructions
- Update
BASE_URLand MojoAuth callback URLs
Environment-Specific Variables
Set different variables per deploy context:
# Production
MOJOAUTH_REDIRECT_URI=https://myapp.com/.netlify/functions/callback
# Deploy Previews
MOJOAUTH_REDIRECT_URI=https://deploy-preview-123--myapp.netlify.app/.netlify/functions/callbackConfigure in: Site settings → Environment variables → Scopes
Add Analytics
Track authentication events:
// In callback function
exports.handler = async (event, context) => {
// ... authentication logic
// Track login event
await fetch('https://analytics.example.com/event', {
method: 'POST',
body: JSON.stringify({
event: 'user_login',
timestamp: new Date(),
user_id: userResponse.data.sub
})
});
// ... return response
};Troubleshooting
Redirect URI Mismatch
Error: redirect_uri_mismatch
Solution:
- Verify callback URL in MojoAuth Dashboard exactly matches:
https://your-site.netlify.app/.netlify/functions/callback - Check for trailing slashes
- Ensure HTTPS (not HTTP) for production
Function Timeout
Error: Function execution timeout
Solution:
- Optimize external API calls
- Use Netlify Background Functions for long-running tasks
- Increase timeout in
netlify.toml:
[functions]
external_node_modules = ["axios"]
[[functions]]
path = "/.netlify/functions/*"
timeout = 30Cookie Not Set
Error: User not staying logged in
Solution:
- Ensure
Secureflag is only set for HTTPS - Check
SameSiteattribute compatibility - Verify cookie domain matches site domain
Environment Variables Not Loading
Error: process.env.MOJOAUTH_CLIENT_ID is undefined
Solution:
- Redeploy after adding environment variables
- Check variable names for typos
- Ensure variables are set in correct deploy context
Security Best Practices
1. Secure Session Storage
Use encrypted, HttpOnly cookies:
const jwt = require('jsonwebtoken');
const sessionToken = jwt.sign(
{ userId: userData.sub, email: userData.email },
process.env.SESSION_SECRET,
{ expiresIn: '7d' }
);
return {
headers: {
'Set-Cookie': `session=${sessionToken}; HttpOnly; Secure; SameSite=Lax; Max-Age=604800`
}
};2. Validate Tokens
Always validate JWT tokens:
const jwt = require('jsonwebtoken');
function validateSession(cookies) {
try {
const sessionCookie = cookies.split(';')
.find(c => c.trim().startsWith('session='));
if (!sessionCookie) return null;
const token = sessionCookie.split('=')[1];
return jwt.verify(token, process.env.SESSION_SECRET);
} catch (err) {
return null;
}
}3. Rate Limiting
Implement rate limiting for auth endpoints:
const rateLimit = new Map();
function checkRateLimit(ip) {
const now = Date.now();
const windowMs = 15 * 60 * 1000; // 15 minutes
const maxRequests = 5;
if (!rateLimit.has(ip)) {
rateLimit.set(ip, { count: 1, resetTime: now + windowMs });
return true;
}
const data = rateLimit.get(ip);
if (now > data.resetTime) {
rateLimit.set(ip, { count: 1, resetTime: now + windowMs });
return true;
}
if (data.count >= maxRequests) {
return false;
}
data.count++;
return true;
}4. CSRF Protection
Add CSRF tokens for state management:
const crypto = require('crypto');
// Generate state token
const state = crypto.randomBytes(32).toString('hex');
// Store in session
// Include in auth URL
const authUrl = `${MOJOAUTH_AUTHORIZE_URL}?state=${state}&...`;
// Validate on callback
if (receivedState !== storedState) {
throw new Error('CSRF validation failed');
}Example: Full-Stack JAMstack App
Complete example with React frontend:
Repository Structure:
my-netlify-app/
├── public/
│ ├── index.html
│ └── favicon.ico
├── src/
│ ├── App.jsx
│ ├── components/
│ │ ├── Login.jsx
│ │ └── Profile.jsx
│ └── index.js
├── netlify/
│ └── functions/
│ ├── auth-login.js
│ ├── callback.js
│ └── logout.js
├── netlify.toml
├── package.json
└── README.mdReact Component:
// src/components/Login.jsx
import { useState, useEffect } from 'react';
export default function Login() {
const [user, setUser] = useState(null);
useEffect(() => {
checkAuth();
}, []);
async function checkAuth() {
const response = await fetch('/.netlify/functions/protected');
if (response.ok) {
const data = await response.json();
setUser(data.user);
}
}
if (user) {
return (
<div>
<p>Welcome, {user.name}!</p>
<a href="/.netlify/functions/logout">Logout</a>
</div>
);
}
return (
<a href="/.netlify/functions/auth-login" className="btn-login">
Login with MojoAuth
</a>
);
}Migration from Other Platforms
From Auth0
- Export users from Auth0
- Import to MojoAuth via Management API
- Update environment variables
- Redeploy Netlify site
From Firebase Auth
- Update Firebase Functions to Netlify Functions
- Replace Firebase SDK with MojoAuth OIDC
- Migrate user data
- Update frontend integration
Resources
- Template Repository: https://github.com/MojoAuth/mojoauth-netlify-template (opens in a new tab)
- Netlify Docs: https://docs.netlify.com/ (opens in a new tab)
- MojoAuth API Reference: https://docs.mojoauth.com/api-reference/ (opens in a new tab)
- Example Apps: Check the GitHub repo for live examples
- Community: Join our Discord for help and best practices
Next Steps
- ✅ Deploy the template to Netlify
- ✅ Configure MojoAuth credentials
- ✅ Customize your site design
- ✅ Add protected routes and pages
- ✅ Set up custom domain
- ✅ Enable analytics and monitoring
- ✅ Add multi-factor authentication (optional)
Need Help?
- Email: support@mojoauth.com
- GitHub Issues: https://github.com/MojoAuth/mojoauth-netlify-template/issues (opens in a new tab)
- Documentation: https://docs.mojoauth.com/ (opens in a new tab)
Deploy Now: Visit the GitHub repository (opens in a new tab) and click "Deploy to Netlify" to get started in minutes!