Site Auth: Add Waymaker Login to Your Site
Learn about Site Auth: Add Waymaker Login to Your Site in WaymakerOS.
Waymaker Site Auth lets any static site or app hosted on Waymaker Host use your existing Waymaker login for authentication. Add a script tag and three lines of JavaScript — your users sign in with their Waymaker account, and your Ambassadors know exactly who is making each request.
Quick Start
1. Add the Auth Script
Include the Waymaker auth client on any page that needs login:
<script src="https://cdn.waymakerone.com/auth.js"></script>
2. Initialize and Check Login
<script>
const wm = WaymakerAuth.init({ appId: 'your-app-id' })
if (!wm.isAuthenticated()) {
wm.login()
}
</script>
That's it. Unauthenticated visitors are redirected to the Waymaker login page, then returned to your site with a valid session.
3. Use the Session
Once authenticated, you have access to the user's identity and a token for API calls:
const user = wm.getUser()
// { id: 'user_abc', email: 'jane@acme.com', name: 'Jane Smith', role: 'admin' }
const token = wm.getToken()
// Use this token when calling your Ambassadors
How It Works
- User visits your protected page (e.g.,
yourdomain.com/admin) WaymakerAuth.init()checks for an existing session in browser storage- No session found —
wm.login()redirects toauth.waymakerone.com - User signs in with their Waymaker account (email, password, or SSO)
- After sign-in, the user is redirected back to your page with a short-lived exchange token
- The auth client automatically exchanges the token for a session and stores it
- Your page now has access to the user's identity and an access token for API calls
The entire flow takes a few seconds. Your site never handles passwords or credentials directly.
API Reference
| Method | Returns | Description |
|---|---|---|
WaymakerAuth.init({ appId }) | WaymakerAuth | Initialize auth with your Host app ID |
wm.isAuthenticated() | boolean | true if the user has a valid session |
wm.login() | void | Redirects to Waymaker login, returns to current page after sign-in |
wm.logout() | void | Ends the session and clears stored credentials |
wm.getToken() | `string | null` |
wm.getUser() | `User | null` |
wm.onAuthChange(callback) | () => void | Calls your function when auth state changes. Returns an unsubscribe function |
User Object
{
id: 'user_abc123', // Waymaker user ID
email: 'jane@acme.com', // Email address
name: 'Jane Smith', // Display name
role: 'admin' // Role within the workspace
}
Full Example: Protected Admin Page
Here is a complete HTML page with authentication and an Ambassador API call:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin</title>
<script src="https://cdn.waymakerone.com/auth.js"></script>
</head>
<body>
<div id="loading">Checking login...</div>
<div id="admin" style="display: none;">
<h1>Welcome, <span id="user-name"></span></h1>
<p>Email: <span id="user-email"></span></p>
<button id="upload-btn">Upload Document</button>
<button id="logout-btn">Sign Out</button>
</div>
<script>
const wm = WaymakerAuth.init({ appId: 'your-app-id' })
if (!wm.isAuthenticated()) {
wm.login() // Redirects to Waymaker login
} else {
// User is signed in — show the admin UI
document.getElementById('loading').style.display = 'none'
document.getElementById('admin').style.display = 'block'
const user = wm.getUser()
document.getElementById('user-name').textContent = user.name
document.getElementById('user-email').textContent = user.email
// Call an Ambassador with the auth token
document.getElementById('upload-btn').addEventListener('click', async () => {
const response = await fetch('https://ambassador.waymakerone.com/your-app/upload', {
method: 'POST',
headers: {
'Authorization': `Bearer ${wm.getToken()}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ title: 'My Document' })
})
if (response.ok) {
alert('Upload successful')
} else if (response.status === 401) {
wm.login() // Session expired — re-authenticate
}
})
// Sign out
document.getElementById('logout-btn').addEventListener('click', () => {
wm.logout()
window.location.reload()
})
}
</script>
</body>
</html>
Validating Tokens in Ambassadors
When your Ambassador receives a request with a Bearer token, validate it against the Context API:
async function handleRequest(request: Request) {
// 1. Extract the token
const token = request.headers.get('Authorization')?.replace('Bearer ', '')
if (!token) {
return new Response('Unauthorized', { status: 401 })
}
// 2. Validate against Context API
const auth = await fetch('https://auth.waymakerone.com/context/auth/validate', {
headers: { 'Authorization': `Bearer ${token}` }
})
if (!auth.ok) {
return new Response('Unauthorized', { status: 401 })
}
// 3. Use the verified identity
const { user, workspace } = await auth.json()
// user.id, user.email, user.role
// workspace.id, workspace.tier
// Now process the request knowing who made it
return new Response(`Hello ${user.name}`, { status: 200 })
}
The Ambassador never handles credentials directly. It receives a token, validates it with one API call, and gets back the user's identity and workspace context.
ES Module Usage
If you prefer ES modules over a script tag:
<script type="module">
import { WaymakerAuth } from 'https://cdn.waymakerone.com/auth.mjs'
const wm = WaymakerAuth.init({ appId: 'your-app-id' })
if (!wm.isAuthenticated()) {
wm.login()
}
</script>
Auth State Changes
Subscribe to authentication changes to update your UI when the user signs in or out:
const unsubscribe = wm.onAuthChange((isAuthenticated) => {
if (isAuthenticated) {
showAdminUI(wm.getUser())
} else {
showLoginPrompt()
}
})
// Later, stop listening
unsubscribe()
Finding Your App ID
Your app ID is assigned when you create an app in Waymaker Host. You can find it:
- In Host, open your app's settings — the app ID is displayed at the top
- Using the CLI:
waymaker host apps list - Using Claude Desktop: "What's the app ID for my app?"
Allowed Domains
For security, each app must register the domains that are allowed to use authentication. Waymaker only redirects back to registered domains after sign-in.
Your app's domains are configured automatically when you set up a custom domain in Host. If you need to add additional domains, update them in your app's settings or contact support.
Token Lifecycle
- Session storage: Tokens are stored in the browser's session storage (cleared when the tab closes)
- Automatic refresh: The auth client refreshes tokens before they expire — no re-login needed during a session
- 1-hour tokens: Access tokens are valid for 1 hour and refreshed automatically
- Sign out: Calling
wm.logout()invalidates the session on the server and clears local storage
Troubleshooting
"Unauthorized" errors from Ambassador
- Confirm your app ID matches the one in Host
- Check that the domain is registered in your app's allowed domains
- Verify the token is being sent in the
Authorizationheader asBearer <token> - If the token has expired, call
wm.login()to start a fresh session
Login redirect loops
- Make sure your app ID is correct
- Verify your domain is in the allowed domains list for that app
- Clear your browser's session storage and try again
Token not found after redirect
The auth client reads the exchange token from the URL after sign-in. If this fails:
- Check that the auth script is loaded before your initialization code
- Ensure nothing else is modifying the URL query parameters on page load
- Try a different browser to rule out extension interference
Related
- Getting Started with Host — Set up your first app
- Ambassadors — Build serverless functions that use auth tokens
- Custom Domains — Configure domains for your app
- Environment Variables — Store secrets for Ambassadors