Turalogin is a hosted passwordless authentication service built on backend-only verification and server-to-server trust. Backend-only verification. Single-use tokens. Server-to-server trust. This is how Turalogin keeps authentication secure.
Authentication tokens are verified server-to-server only. Your backend receives the token from the URL parameter and immediately verifies it with Turalogin's API. The token never enters JavaScript scope, eliminating XSS-based token theft.
Each magic link works exactly once and expires after 15 minutes. Once used, the token is marked as consumed in the database. Even if an attacker intercepts a link, it becomes useless after the first use.
All token verification happens on your backend via API calls to Turalogin's servers. There's no client-side verification, no JWT decoding in the browser, no tokens exposed to JavaScript at all.
After verification, Turalogin hands you the user's email and gets out of the way. You create your own session using httpOnly cookies, session stores, or whatever mechanism you prefer. You have full control over session duration and invalidation.
Frontend sends email to your backend. No sensitive data is sent to Turalogin yet.
Your backend calls Turalogin's /auth/start endpoint with the email and your validation URL. This is a server-to-server call with your API key.
Turalogin creates a cryptographically random token (48 characters), stores it in the database with a 15-minute expiration, and sends an email to the user.
The email contains a link to your validation URL with the token as a query parameter. User clicks it and lands on your backend route.
Your backend extracts the token from the URL and calls Turalogin's /auth/verify endpoint server-to-server. The token never reaches your frontend.
Turalogin checks: Does the token exist? Is it unused? Has it expired? If all checks pass, it marks the token as used and returns the user's email.
Your backend receives the verified email, creates your own session (httpOnly cookie recommended), and redirects the user. Turalogin is done.
Since tokens never enter JavaScript scope, XSS vulnerabilities can't steal them. Even if an attacker injects malicious scripts, there's nothing to steal.
When you set session cookies with sameSite='lax' and httpOnly=true, CSRF attacks are blocked. The cookie can't be accessed by JavaScript and won't be sent cross-origin.
Links expire in 15 minutes and work exactly once. An attacker intercepting a link has a narrow window and can only use it once before the legitimate user.
V2 invite links share the same single-use, server-to-server verification as login. Custom expiry (up to 7 days) still enforces one-time use and backend-only verification. Metadata is stored server-side and never exposed in the link.
There are no password hashes to crack, no credentials to stuff, no database of secrets to extract. Email addresses are low-value targets.
By using email as the authentication factor, you inherit Gmail/Outlook/etc.'s security infrastructure. 2FA, anomaly detection, and dedicated security teams.
You can immediately invalidate sessions server-side, track login activity, detect suspicious behavior, and implement custom security policies.
After Turalogin verifies the token, create your session with these security best practices:
// After token verification succeeds
const session = await createSession({
userId: user.id,
email: user.email,
expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) // 30 days
});
// Set httpOnly cookie
res.setHeader('Set-Cookie', serialize('session', session.token, {
httpOnly: true, // Can't be accessed by JavaScript
secure: true, // Only sent over HTTPS
sameSite: 'lax', // CSRF protection
maxAge: 30 * 24 * 60 * 60, // 30 days
path: '/'
}));httpOnly: trueJavaScript can't access the cookie. Eliminates XSS token theft.
secure: trueCookie only sent over HTTPS. Prevents interception on insecure connections.
sameSite: 'lax'Cookie not sent on cross-site requests. Blocks CSRF attacks.
maxAge: 30 daysYou control session duration. Make it shorter or longer based on your security requirements.
Turalogin verifies email addresses. That's all. Access control, authorization, domain restrictions are your responsibility. Common patterns:
Most common need: Restricting authentication to specific email domains (e.g., only @yourcompany.com emails).
Implementation: Validate the email domain in your backend BEFORE calling Turalogin's /auth/start endpoint.
// In your /api/auth/login endpoint, BEFORE calling Turalogin
const ALLOWED_DOMAINS = ["yourcompany.com", "partner.com"];
const domain = email.split("@")[1]?.toLowerCase();
if (!ALLOWED_DOMAINS.includes(domain)) {
return Response.json(
{ error: "Only company email addresses are allowed" },
{ status: 403 }
);
}
// Only if domain is allowed, proceed with Turalogin
const response = await fetch('https://api.turalogin.com/api/v2/auth/start', {
// ... rest of Turalogin call
});Critical: Validation must be server-side. Client-side alone can be bypassed.
For apps that should only allow specific email addresses (not just domains), check against an allowlist before calling Turalogin.
// Check against database of allowed users
const allowedUser = await db.allowedUsers.findUnique({
where: { email: email.toLowerCase() }
});
if (!allowedUser) {
return Response.json(
{ error: "You don't have access to this application" },
{ status: 403 }
);
}
// Proceed with Turalogin if user is allowedAfter Turalogin verifies the email, look up the user's role in your database and attach it to the session. This is entirely separate from authentication.
// After successful Turalogin verification
const { jwt, user } = await turaloginVerify(token);
// Look up user's role in your database
const userProfile = await db.users.findUnique({
where: { email: user.email }
});
// Create session with role information
const session = await createSession({
email: user.email,
role: userProfile.role, // admin, user, viewer, etc.
permissions: userProfile.permissions
});Detect new users after verification and redirect them to an onboarding flow instead of the main dashboard.
// After Turalogin verification succeeds
const existingUser = await db.users.findUnique({
where: { email: user.email }
});
if (!existingUser) {
// Create new user record
await db.users.create({
data: {
email: user.email,
createdAt: new Date(),
onboardingCompleted: false
}
});
// Redirect to onboarding
redirect('/onboarding');
} else {
// Existing user - go to dashboard
redirect('/dashboard');
}Key: Turalogin verifies email control. Who can sign up, what they access, their role: your application logic. Implement in your backend before or after calling Turalogin.
Every security system has a threat model. What Turalogin protects against and what it doesn't:
Note: Email compromise is the shared trust boundary. If an attacker controls the user's email, they can reset passwords, receive 2FA codes, and access password reset links on any service. Turalogin recognizes email as the ultimate authority and builds security around that reality.