Back to home

Integration First, Frontend Optional

Turalogin is built for backends. If your server can make an HTTP request, you can add email-based authentication in minutes. No redirects, no hosted UI, no frontend lock-in.

Every example below follows the same pattern: start auth, verify email, exchange proof for a token. The framework fades away.

Set Up with AI in Seconds

Copy a prompt to Cursor, Claude, or ChatGPT to scaffold authentication instantly.

More framework-specific prompts available on each integration page below.

Next.js

Works naturally with API routes, route handlers, or server actions. Your Next.js backend calls Turalogin to start auth, then exchanges the proof server-side and sets its own session cookie.

This is the primary reference implementation and what powers the Turalogin site itself.

// app/api/auth/start/route.ts
import { turalogin } from '@/lib/turalogin';

export async function POST(req: Request) {
  const { email } = await req.json();
  
  // Start authentication - sends OTP to user's email
  const { sessionId } = await turalogin.startAuth({ email });
  
  return Response.json({ sessionId });
}

// app/api/auth/verify/route.ts
export async function POST(req: Request) {
  const { sessionId, code } = await req.json();
  
  // Exchange the code for a JWT
  const { token, user } = await turalogin.verifyCode({ sessionId, code });
  
  // Create your own session
  const session = await createSession(user);
  
  return Response.json({ success: true }, {
    headers: { 'Set-Cookie': `session=${session.id}; HttpOnly; Secure` }
  });
}
View full examples

Node.js (Express, Fastify)

Drop-in for any Node backend. Use a single service file to call Turalogin from your login endpoint. Works the same whether you are running Express, Fastify, Hapi, or a custom server.

If you can handle JSON over HTTP, you are done.

// Express example
import express from 'express';

const app = express();

app.post('/auth/start', async (req, res) => {
  const { email } = req.body;
  
  const response = await fetch('https://api.turalogin.com/auth/start', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.TURALOGIN_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ email }),
  });
  
  const { sessionId } = await response.json();
  res.json({ sessionId });
});

app.post('/auth/verify', async (req, res) => {
  const { sessionId, code } = req.body;
  
  const response = await fetch('https://api.turalogin.com/auth/verify', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.TURALOGIN_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ sessionId, code }),
  });
  
  const { token, user } = await response.json();
  
  // Create your session
  req.session.userId = user.id;
  res.json({ success: true });
});
View full examples

Bun and Deno

Modern runtimes work out of the box. No SDK required. Fetch-based examples using native APIs. Clean, fast, and edge-friendly.

// Bun server example
const server = Bun.serve({
  port: 3000,
  async fetch(req) {
    const url = new URL(req.url);
    
    if (url.pathname === '/auth/start' && req.method === 'POST') {
      const { email } = await req.json();
      
      const res = await fetch('https://api.turalogin.com/auth/start', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${Bun.env.TURALOGIN_API_KEY}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ email }),
      });
      
      return new Response(JSON.stringify(await res.json()), {
        headers: { 'Content-Type': 'application/json' },
      });
    }
    
    return new Response('Not Found', { status: 404 });
  },
});
View full examples

Python (FastAPI, Flask, Django)

Simple server-to-server integration. One request to start auth. One request to exchange proof. Token verification happens locally using standard JWT libraries.

FastAPI examples are especially clean due to async support.

# FastAPI example
from fastapi import FastAPI, HTTPException
import httpx
import os

app = FastAPI()
TURALOGIN_API_KEY = os.environ["TURALOGIN_API_KEY"]

@app.post("/auth/start")
async def start_auth(email: str):
    async with httpx.AsyncClient() as client:
        response = await client.post(
            "https://api.turalogin.com/auth/start",
            headers={"Authorization": f"Bearer {TURALOGIN_API_KEY}"},
            json={"email": email},
        )
        return response.json()

@app.post("/auth/verify")
async def verify_auth(session_id: str, code: str):
    async with httpx.AsyncClient() as client:
        response = await client.post(
            "https://api.turalogin.com/auth/verify",
            headers={"Authorization": f"Bearer {TURALOGIN_API_KEY}"},
            json={"sessionId": session_id, "code": code},
        )
        data = response.json()
        # Create your own session here
        return {"success": True, "user": data["user"]}
View full examples

Ruby (Rails, Sinatra)

Fits naturally into controller actions or service objects. Rails apps can treat Turalogin like any external identity provider without OAuth overhead.

# Rails controller example
class AuthController < ApplicationController
  def start
    response = HTTParty.post(
      "https://api.turalogin.com/auth/start",
      headers: {
        "Authorization" => "Bearer #{ENV['TURALOGIN_API_KEY']}",
        "Content-Type" => "application/json"
      },
      body: { email: params[:email] }.to_json
    )
    
    render json: response.parsed_response
  end
  
  def verify
    response = HTTParty.post(
      "https://api.turalogin.com/auth/verify",
      headers: {
        "Authorization" => "Bearer #{ENV['TURALOGIN_API_KEY']}",
        "Content-Type" => "application/json"
      },
      body: { sessionId: params[:session_id], code: params[:code] }.to_json
    )
    
    data = response.parsed_response
    session[:user_id] = data["user"]["id"]
    render json: { success: true }
  end
end
View full examples

Java (Spring Boot)

Strong fit for enterprise and internal tools. Use standard REST clients. Tokens integrate cleanly with Spring Security if desired, or you can manage sessions manually.

// Spring Boot controller
@RestController
@RequestMapping("/auth")
public class AuthController {
    
    @Value("${turalogin.api-key}")
    private String apiKey;
    
    private final RestTemplate restTemplate = new RestTemplate();
    
    @PostMapping("/start")
    public ResponseEntity<?> startAuth(@RequestBody Map<String, String> body) {
        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(apiKey);
        headers.setContentType(MediaType.APPLICATION_JSON);
        
        HttpEntity<Map<String, String>> request = new HttpEntity<>(
            Map.of("email", body.get("email")), headers
        );
        
        return restTemplate.postForEntity(
            "https://api.turalogin.com/auth/start",
            request,
            Map.class
        );
    }
    
    @PostMapping("/verify")
    public ResponseEntity<?> verifyAuth(@RequestBody Map<String, String> body) {
        // Similar pattern - call Turalogin, then create your session
        // ...
    }
}
View full examples

Go

Lightweight and explicit. Use net/http or any HTTP client. JWT verification is fast and simple. Ideal for APIs and microservices.

package main

import (
    "bytes"
    "encoding/json"
    "net/http"
    "os"
)

func startAuth(w http.ResponseWriter, r *http.Request) {
    var body struct {
        Email string `json:"email"`
    }
    json.NewDecoder(r.Body).Decode(&body)
    
    payload, _ := json.Marshal(map[string]string{"email": body.Email})
    
    req, _ := http.NewRequest("POST", "https://api.turalogin.com/auth/start", bytes.NewBuffer(payload))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("TURALOGIN_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    
    client := &http.Client{}
    resp, _ := client.Do(req)
    defer resp.Body.Close()
    
    var result map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&result)
    
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(result)
}
View full examples

PHP (Laravel, Symfony)

Works well for traditional web apps and APIs. Turalogin slots into existing auth flows without replacing your user model or session handling.

<?php
// Laravel controller example

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;

class AuthController extends Controller
{
    public function start(Request $request)
    {
        $response = Http::withToken(config('services.turalogin.key'))
            ->post('https://api.turalogin.com/auth/start', [
                'email' => $request->email,
            ]);
        
        return $response->json();
    }
    
    public function verify(Request $request)
    {
        $response = Http::withToken(config('services.turalogin.key'))
            ->post('https://api.turalogin.com/auth/verify', [
                'sessionId' => $request->session_id,
                'code' => $request->code,
            ]);
        
        $data = $response->json();
        
        // Create your session
        auth()->loginUsingId($data['user']['id']);
        
        return ['success' => true];
    }
}
View full examples

.NET (ASP.NET Core)

First-class backend support. Use HttpClient for the exchange and standard middleware for session handling or token validation.

// ASP.NET Core controller
[ApiController]
[Route("auth")]
public class AuthController : ControllerBase
{
    private readonly HttpClient _httpClient;
    private readonly string _apiKey;

    public AuthController(IConfiguration config)
    {
        _httpClient = new HttpClient();
        _apiKey = config["Turalogin:ApiKey"];
        _httpClient.DefaultRequestHeaders.Authorization = 
            new AuthenticationHeaderValue("Bearer", _apiKey);
    }

    [HttpPost("start")]
    public async Task<IActionResult> Start([FromBody] StartRequest request)
    {
        var response = await _httpClient.PostAsJsonAsync(
            "https://api.turalogin.com/auth/start",
            new { email = request.Email }
        );
        
        return Ok(await response.Content.ReadFromJsonAsync<object>());
    }

    [HttpPost("verify")]
    public async Task<IActionResult> Verify([FromBody] VerifyRequest request)
    {
        var response = await _httpClient.PostAsJsonAsync(
            "https://api.turalogin.com/auth/verify",
            new { sessionId = request.SessionId, code = request.Code }
        );
        
        // Create your session and return
        return Ok(new { success = true });
    }
}
View full examples

Serverless Platforms

Works with AWS Lambda, Vercel Functions, Cloudflare Workers, and similar environments. No long-lived connections. No shared state required. All calls are stateless and fast.

// Cloudflare Worker example
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    
    if (url.pathname === '/auth/start' && request.method === 'POST') {
      const { email } = await request.json();
      
      const response = await fetch('https://api.turalogin.com/auth/start', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${env.TURALOGIN_API_KEY}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ email }),
      });
      
      return new Response(JSON.stringify(await response.json()), {
        headers: { 'Content-Type': 'application/json' },
      });
    }
    
    return new Response('Not Found', { status: 404 });
  },
};
View full examples

Consistent API Across All Frameworks

Every backend uses the same small surface area:

POST /auth/start    → { sessionId }     // Start authentication
POST /auth/verify   → { token, user }   // Exchange code for JWT
POST /auth/refresh  → { token }         // Refresh expired token (optional)

Once you understand one example, you understand them all.

Why This Matters

Auth should not dictate your stack.

Turalogin works the same whether you are shipping a Next.js SaaS, a Python API, an internal admin tool, or a dozen services at once.

You do not need to adopt a new auth model.

You do not need frontend rewrites.

You keep your users, sessions, and app logic.

Backend-first by design. Simple everywhere.

Ready to integrate?

Create your Turalogin account and get your API key in minutes.