CMS
Netlify

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


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

  1. Visit the Netlify Template Marketplace (opens in a new tab)
  2. Search for "MojoAuth"
  3. Click "Deploy to Netlify"
  4. Connect your GitHub account
  5. Configure environment variables (see below)
  6. Click "Save & Deploy"

Option 2: Deploy from GitHub

  1. Visit the template repository: https://github.com/MojoAuth/mojoauth-netlify-template (opens in a new tab)
  2. Click the "Deploy to Netlify" button
  3. Authorize Netlify to access your GitHub account
  4. Choose a repository name
  5. Configure environment variables
  6. 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-here

To add environment variables in Netlify:

  1. Go to your site in Netlify Dashboard
  2. Navigate to Site settingsEnvironment variables
  3. Click Add a variable
  4. 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/callback
    • http://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.app
    • http://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-site

2. Install Dependencies

npm install

3. 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-secret

4. Run Netlify Dev

netlify dev

This starts a local server at http://localhost:8888 with Netlify Functions support.

5. Test Authentication

  1. Open http://localhost:8888
  2. Click "Login with MojoAuth"
  3. Complete authentication on MojoAuth Hosted Login Page
  4. 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 deploys

Deploy Previews

Netlify creates deploy previews for pull requests:

  1. Create a new branch
  2. Make changes and push
  3. Open a pull request
  4. Netlify generates a preview URL
  5. Test before merging

Manual Deploys

Trigger manual deploys from the Netlify Dashboard:

  1. Go to Deploys tab
  2. Click Trigger deployDeploy site

Advanced Configuration

Custom Domain

  1. In Netlify Dashboard → Domain settings
  2. Click Add custom domain
  3. Follow DNS configuration instructions
  4. Update BASE_URL and 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/callback

Configure in: Site settingsEnvironment variablesScopes

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 = 30

Cookie Not Set

Error: User not staying logged in

Solution:

  • Ensure Secure flag is only set for HTTPS
  • Check SameSite attribute 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.md

React 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

  1. Export users from Auth0
  2. Import to MojoAuth via Management API
  3. Update environment variables
  4. Redeploy Netlify site

From Firebase Auth

  1. Update Firebase Functions to Netlify Functions
  2. Replace Firebase SDK with MojoAuth OIDC
  3. Migrate user data
  4. Update frontend integration

Resources


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?


Deploy Now: Visit the GitHub repository (opens in a new tab) and click "Deploy to Netlify" to get started in minutes!