All integrations

PHP Integration

Laravel, Symfony, and vanilla PHP

Turalogin works well for traditional PHP web apps and APIs. Start auth to send a magic link email, handle the callback when users click the link, and verify the token. It slots into existing auth flows without replacing your user model or session handling.

  • Works with Laravel, Symfony, CodeIgniter, and vanilla PHP
  • Magic link flow with customizable callback URL
  • Uses Laravel HTTP client, Guzzle, or cURL
  • Compatible with existing user models
  • Standard PHP session handling

Implementation Examples

1. Environment Configuration

Set up your environment variables for local development and production.

.env
1# Your Turalogin API key from the dashboard
2TURALOGIN_API_KEY=tl_live_xxxxxxxxxxxxx
3
4# The URL where magic links will redirect to
5# Development:
6APP_LOGIN_VALIDATION_URL=http://localhost:8000/auth/callback
7
8# Production (update for your domain):
9# APP_LOGIN_VALIDATION_URL=https://myapp.com/auth/callback

2. Start Authentication (Laravel)

Create a controller method to initiate authentication. This sends a magic link to the user's email.

app/Http/Controllers/AuthController.php
1<?php
2
3namespace App\Http\Controllers;
4
5use Illuminate\Http\Request;
6use Illuminate\Support\Facades\Http;
7
8class AuthController extends Controller
9{
10 private string $apiKey;
11 private string $apiUrl = 'https://api.turalogin.com/api/v1';
12 private string $validationUrl;
13
14 public function __construct()
15 {
16 $this->apiKey = config('services.turalogin.key');
17 $this->validationUrl = config('services.turalogin.validation_url');
18 }
19
20 public function start(Request $request)
21 {
22 $request->validate([
23 'email' => 'required|email',
24 ]);
25
26 $response = Http::withToken($this->apiKey)
27 ->post("{$this->apiUrl}/auth/start", [
28 'email' => $request->email,
29 'validationUrl' => $this->validationUrl, // Where the magic link redirects to
30 ]);
31
32 if ($response->failed()) {
33 return response()->json(
34 $response->json(),
35 $response->status()
36 );
37 }
38
39 return response()->json([
40 'success' => true,
41 'message' => 'Check your email for the login link',
42 ]);
43 }
44}

3. Handle Magic Link Callback

Create a callback method that receives the token from the magic link and verifies it.

app/Http/Controllers/AuthController.php
1public function callback(Request $request)
2{
3 $token = $request->query('token');
4
5 if (!$token) {
6 return redirect('/login')->with('error', 'Invalid login link');
7 }
8
9 $response = Http::withToken($this->apiKey)
10 ->post("{$this->apiUrl}/auth/verify", [
11 'sessionId' => $token,
12 ]);
13
14 if ($response->failed()) {
15 return redirect('/login')->with('error', 'Login link is invalid or expired');
16 }
17
18 $data = $response->json();
19 $userData = $data['user'];
20
21 // Find or create user
22 $user = User::firstOrCreate(
23 ['email' => $userData['email']],
24 ['turalogin_id' => $userData['id']]
25 );
26
27 // Update last login
28 $user->update(['last_login_at' => now()]);
29
30 // Log the user in
31 auth()->login($user, true);
32
33 // Store Turalogin token if needed
34 session(['turalogin_token' => $data['token']]);
35
36 return redirect('/dashboard')->with('success', 'Successfully signed in!');
37}
38
39public function logout(Request $request)
40{
41 auth()->logout();
42 $request->session()->invalidate();
43 $request->session()->regenerateToken();
44
45 return response()->json(['success' => true]);
46}

4. Turalogin Service Class

A service class that encapsulates Turalogin API interactions.

app/Services/TuraloginService.php
1<?php
2
3namespace App\Services;
4
5use Illuminate\Support\Facades\Http;
6use App\Exceptions\TuraloginException;
7
8class TuraloginService
9{
10 private string $apiKey;
11 private string $validationUrl;
12 private string $baseUrl = 'https://api.turalogin.com/api/v1';
13
14 public function __construct()
15 {
16 $this->apiKey = config('services.turalogin.key');
17 $this->validationUrl = config('services.turalogin.validation_url');
18 }
19
20 public function startAuth(string $email): void
21 {
22 $this->request('/auth/start', [
23 'email' => $email,
24 'validationUrl' => $this->validationUrl,
25 ]);
26 }
27
28 public function verifyToken(string $token): array
29 {
30 return $this->request('/auth/verify', [
31 'sessionId' => $token,
32 ]);
33 }
34
35 private function request(string $endpoint, array $data): array
36 {
37 $response = Http::withToken($this->apiKey)
38 ->post("{$this->baseUrl}{$endpoint}", $data);
39
40 if ($response->failed()) {
41 $error = $response->json();
42 throw new TuraloginException(
43 $error['error'] ?? 'Unknown error',
44 $error['code'] ?? 'UNKNOWN',
45 $response->status()
46 );
47 }
48
49 return $response->json();
50 }
51}
52
53// app/Exceptions/TuraloginException.php
54namespace App\Exceptions;
55
56use Exception;
57
58class TuraloginException extends Exception
59{
60 public string $errorCode;
61 public int $statusCode;
62
63 public function __construct(string $message, string $code, int $status)
64 {
65 parent::__construct($message);
66 $this->errorCode = $code;
67 $this->statusCode = $status;
68 }
69}

5. Service Configuration

Add Turalogin configuration to your services config file.

config/services.php
1<?php
2
3return [
4 // ... other services
5
6 'turalogin' => [
7 'key' => env('TURALOGIN_API_KEY'),
8 'validation_url' => env('APP_LOGIN_VALIDATION_URL'),
9 ],
10];

6. Vanilla PHP Alternative

For projects not using a framework, use cURL directly.

auth.php
1<?php
2
3session_start();
4
5define('TURALOGIN_API_KEY', getenv('TURALOGIN_API_KEY'));
6define('TURALOGIN_API_URL', 'https://api.turalogin.com/api/v1');
7define('VALIDATION_URL', getenv('APP_LOGIN_VALIDATION_URL'));
8
9function turaloginRequest(string $endpoint, array $data): array
10{
11 $ch = curl_init(TURALOGIN_API_URL . $endpoint);
12
13 curl_setopt_array($ch, [
14 CURLOPT_RETURNTRANSFER => true,
15 CURLOPT_POST => true,
16 CURLOPT_POSTFIELDS => json_encode($data),
17 CURLOPT_HTTPHEADER => [
18 'Authorization: Bearer ' . TURALOGIN_API_KEY,
19 'Content-Type: application/json',
20 ],
21 ]);
22
23 $response = curl_exec($ch);
24 $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
25 curl_close($ch);
26
27 $result = json_decode($response, true);
28
29 if ($statusCode !== 200) {
30 throw new Exception($result['error'] ?? 'Unknown error', $statusCode);
31 }
32
33 return $result;
34}
35
36// Handle start auth
37if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_GET['action'] === 'start') {
38 $input = json_decode(file_get_contents('php://input'), true);
39
40 try {
41 turaloginRequest('/auth/start', [
42 'email' => $input['email'],
43 'validationUrl' => VALIDATION_URL,
44 ]);
45 echo json_encode(['success' => true, 'message' => 'Check your email']);
46 } catch (Exception $e) {
47 http_response_code($e->getCode());
48 echo json_encode(['error' => $e->getMessage()]);
49 }
50 exit;
51}
52
53// Handle callback
54if ($_SERVER['REQUEST_METHOD'] === 'GET' && $_GET['action'] === 'callback') {
55 $token = $_GET['token'] ?? null;
56
57 if (!$token) {
58 header('Location: /login?error=invalid_link');
59 exit;
60 }
61
62 try {
63 $result = turaloginRequest('/auth/verify', ['sessionId' => $token]);
64
65 // Create session
66 $_SESSION['user_id'] = $result['user']['id'];
67 $_SESSION['email'] = $result['user']['email'];
68
69 header('Location: /dashboard');
70 } catch (Exception $e) {
71 header('Location: /login?error=verification_failed');
72 }
73 exit;
74}

Complete Laravel Controller

A complete Laravel controller with magic link authentication and dependency injection.

app/Http/Controllers/AuthController.php
1<?php
2
3namespace App\Http\Controllers;
4
5use App\Models\User;
6use App\Services\TuraloginService;
7use App\Exceptions\TuraloginException;
8use Illuminate\Http\Request;
9use Illuminate\Http\JsonResponse;
10use Illuminate\Http\RedirectResponse;
11
12class AuthController extends Controller
13{
14 public function __construct(
15 private TuraloginService $turalogin
16 ) {}
17
18 public function start(Request $request): JsonResponse
19 {
20 $request->validate(['email' => 'required|email']);
21
22 try {
23 $this->turalogin->startAuth($request->email);
24 return response()->json([
25 'success' => true,
26 'message' => 'Check your email for the login link',
27 ]);
28 } catch (TuraloginException $e) {
29 return response()->json(
30 ['error' => $e->getMessage()],
31 $e->statusCode
32 );
33 }
34 }
35
36 public function callback(Request $request): RedirectResponse
37 {
38 $token = $request->query('token');
39
40 if (!$token) {
41 return redirect('/login')->with('error', 'Invalid login link');
42 }
43
44 try {
45 $result = $this->turalogin->verifyToken($token);
46
47 // Find or create user
48 $user = User::firstOrCreate(
49 ['email' => $result['user']['email']],
50 [
51 'turalogin_id' => $result['user']['id'],
52 'name' => $result['user']['email'],
53 ]
54 );
55
56 $user->update(['last_login_at' => now()]);
57
58 // Log in
59 auth()->login($user, true);
60 session(['turalogin_token' => $result['token']]);
61
62 return redirect('/dashboard')->with('success', 'Successfully signed in!');
63
64 } catch (TuraloginException $e) {
65 return redirect('/login')->with('error', 'Login link is invalid or expired');
66 }
67 }
68
69 public function logout(Request $request): JsonResponse
70 {
71 auth()->logout();
72 $request->session()->invalidate();
73 $request->session()->regenerateToken();
74
75 return response()->json(['success' => true]);
76 }
77
78 public function me(Request $request): JsonResponse
79 {
80 return response()->json([
81 'user' => $request->user()->only(['id', 'email', 'name']),
82 ]);
83 }
84}
85
86// routes/web.php
87use App\Http\Controllers\AuthController;
88
89Route::post('/auth/start', [AuthController::class, 'start']);
90Route::get('/auth/callback', [AuthController::class, 'callback']);
91Route::post('/auth/logout', [AuthController::class, 'logout'])->middleware('auth');
92Route::get('/auth/me', [AuthController::class, 'me'])->middleware('auth');

Ready to integrate?

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