🌐 Multi-Domain Setup
Handle authentication across production, staging, dev, and subdomains with a single callback URL.
How It Works
Gammal Tech allows you to whitelist multiple domains but uses only ONE callback URL. This means users can login from any of your whitelisted domains, but they all redirect through your main callback.
Security and simplicity. One callback URL means one place to handle tokens, easier debugging, and reduced attack surface. The SDK handles routing users back to their origin.
Configuration Steps
Login to Developer Portal
Go to my.gammal.tech and access your project settings.
Add All Your Domains
Whitelist every domain where users might click the login button: production, staging, dev, subdomains, and localhost for development.
Set Your Callback URL
Choose ONE URL on your primary domain (usually production) that will receive all authentication callbacks.
Create the Callback Page
Create the callback page that captures the token and handles the redirect back to the user's origin.
Example Configuration
Here's a typical multi-domain setup for a SaaS application:
| Domain | Environment | Purpose |
|---|---|---|
myapp.com |
Production | Main marketing site |
app.myapp.com |
Production | Main application |
staging.myapp.com |
Staging | Pre-production testing |
dev.myapp.com |
Staging | Development testing |
localhost:3000 |
Development | Local development |
localhost:5173 |
Development | Vite dev server |
Callback URL: https://myapp.com/auth-callback.html
Callback Page Implementation
Your callback page needs to capture the token and redirect users back to where they came from. Here's a complete implementation:
<!DOCTYPE html>
<html>
<head>
<title>Authenticating...</title>
<script src="https://api.gammal.tech/sdk-web.js"></script>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
font-family: system-ui, sans-serif;
background: #0a0a0f;
color: white;
}
.loader { text-align: center; }
.spinner {
width: 40px;
height: 40px;
border: 3px solid rgba(255,255,255,0.1);
border-top-color: #6366f1;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 16px;
}
@keyframes spin { to { transform: rotate(360deg); } }
</style>
</head>
<body>
<div class="loader">
<div class="spinner"></div>
<p>Completing login...</p>
</div>
<script>
(async function() {
// Get token and origin from URL
const params = new URLSearchParams(window.location.search);
const token = params.get('token');
const origin = params.get('origin');
const returnPath = params.get('return') || '/';
if (token) {
// Store token
sessionStorage.setItem('gammaltech_token', token);
// If opened as popup, send to parent and close
if (window.opener) {
window.opener.postMessage(
{ type: 'gammaltech_auth', token: token },
'*'
);
window.close();
return;
}
// If same domain, redirect to return path
if (!origin || origin === window.location.origin) {
window.location.href = returnPath;
return;
}
// Cross-domain: redirect with token
const redirectUrl = new URL(returnPath, origin);
redirectUrl.searchParams.set('token', token);
window.location.href = redirectUrl.toString();
} else {
// No token - authentication failed
document.querySelector('.loader').innerHTML =
'<p>Authentication failed. <a href="/">Try again</a></p>';
}
})();
</script>
</body>
</html>
Handling Token on Origin Pages
When users are redirected back to non-callback domains, they may have the token in the URL. Handle this on your app pages:
<script src="https://api.gammal.tech/sdk-web.js"></script>
<script>
// Check if we received a token via redirect
(function() {
const params = new URLSearchParams(window.location.search);
const token = params.get('token');
if (token) {
// Store the token
sessionStorage.setItem('gammaltech_token', token);
// Clean URL (remove token from address bar)
params.delete('token');
const cleanUrl = window.location.pathname +
(params.toString() ? '?' + params.toString() : '');
history.replaceState({}, '', cleanUrl);
}
// Now check if user is logged in
if (GammalTech.isLoggedIn()) {
console.log('User is authenticated!');
// Initialize your app for logged-in user
}
})();
</script>
Passing Origin to Login
For cross-domain scenarios, you may want to pass the user's origin to ensure they return to the right place:
async function loginWithOrigin() {
// Store where user came from before login
sessionStorage.setItem('auth_return_url', window.location.href);
// Standard login - SDK handles the rest
const token = await GammalTech.login();
if (token) {
// Check if we need to redirect somewhere
const returnUrl = sessionStorage.getItem('auth_return_url');
sessionStorage.removeItem('auth_return_url');
if (returnUrl && returnUrl !== window.location.href) {
window.location.href = returnUrl;
}
}
}
Real-World Example: MeNooN
MeNooN (menoon.org) is a website builder that demonstrates multi-domain authentication. Users create sites on subdomains like mysite.menoon.org, but all authentication flows through the main domain.
| Domain | Role |
|---|---|
menoon.org |
Main site + Callback URL |
*.menoon.org |
User-created subdomains (dynamic) |
menoon.us |
International users (USD payments) |
Contact Gammal Tech to enable wildcard subdomain whitelisting (*.yourdomain.com) for platforms with dynamic subdomains.
Troubleshooting
Problem: User logs in on app.mysite.com but isn't logged in on mysite.com.
Solution: sessionStorage is per-origin. Use the redirect pattern above or implement a token sync mechanism via your callback page.
Problem: After login, user ends up on production instead of staging.
Solution: Ensure your callback page correctly reads and uses the origin parameter from the URL.
Problem: Login fails on localhost:3000.
Solution: Add the full origin including port (localhost:3000, not just localhost) to your whitelist.
AI Prompt for Vibe Coding
Multi-DomainCopy this prompt for help with multi-domain authentication: