All integrations

.NET Integration

ASP.NET Core and enterprise applications

Turalogin provides first-class backend support for .NET applications. Start auth to send a magic link email, handle the callback when users click the link, and verify the token. Works seamlessly with ASP.NET Core's authentication system.

  • Works with ASP.NET Core, Minimal APIs, and Web API
  • Magic link flow with customizable callback URL
  • HttpClient with dependency injection
  • Compatible with ASP.NET Core Identity
  • Full async/await support

Implementation Examples

1. Application Configuration

Configure your settings in appsettings.json for local development and production.

appsettings.json
1{
2 "Turalogin": {
3 "ApiKey": "your-api-key-here",
4 "ValidationUrl": "http://localhost:5000/auth/callback"
5 }
6}
7
8// For production, use environment variables or user secrets:
9// dotnet user-secrets set "Turalogin:ApiKey" "tl_live_xxx"
10// dotnet user-secrets set "Turalogin:ValidationUrl" "https://myapp.com/auth/callback"

2. Start Authentication

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

Controllers/AuthController.cs
1using Microsoft.AspNetCore.Mvc;
2using System.Text.Json;
3
4namespace MyApp.Controllers;
5
6[ApiController]
7[Route("auth")]
8public class AuthController : ControllerBase
9{
10 private readonly TuraloginService _turalogin;
11
12 public AuthController(TuraloginService turalogin)
13 {
14 _turalogin = turalogin;
15 }
16
17 [HttpPost("start")]
18 public async Task<IActionResult> Start([FromBody] StartAuthRequest request)
19 {
20 if (string.IsNullOrEmpty(request.Email))
21 {
22 return BadRequest(new { error = "Email is required" });
23 }
24
25 try
26 {
27 await _turalogin.StartAuthAsync(request.Email);
28 return Ok(new {
29 success = true,
30 message = "Check your email for the login link"
31 });
32 }
33 catch (TuraloginException ex)
34 {
35 return StatusCode(ex.StatusCode, new { error = ex.Message });
36 }
37 }
38}
39
40public record StartAuthRequest(string Email);

3. Handle Magic Link Callback

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

Controllers/AuthController.cs
1[HttpGet("callback")]
2public async Task<IActionResult> Callback([FromQuery] string token)
3{
4 if (string.IsNullOrEmpty(token))
5 {
6 return Redirect("/login?error=invalid_link");
7 }
8
9 try
10 {
11 var result = await _turalogin.VerifyTokenAsync(token);
12
13 // Create claims for the user
14 var claims = new List<Claim>
15 {
16 new Claim(ClaimTypes.NameIdentifier, result.User.Id),
17 new Claim(ClaimTypes.Email, result.User.Email),
18 };
19
20 var claimsIdentity = new ClaimsIdentity(
21 claims,
22 CookieAuthenticationDefaults.AuthenticationScheme
23 );
24
25 var authProperties = new AuthenticationProperties
26 {
27 IsPersistent = true,
28 ExpiresUtc = DateTimeOffset.UtcNow.AddDays(7),
29 };
30
31 await HttpContext.SignInAsync(
32 CookieAuthenticationDefaults.AuthenticationScheme,
33 new ClaimsPrincipal(claimsIdentity),
34 authProperties
35 );
36
37 return Redirect("/dashboard");
38 }
39 catch (TuraloginException)
40 {
41 return Redirect("/login?error=verification_failed");
42 }
43}
44
45[HttpPost("logout")]
46[Authorize]
47public async Task<IActionResult> Logout()
48{
49 await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
50 return Ok(new { success = true });
51}

4. Turalogin Service

A service class that handles all Turalogin API interactions.

Services/TuraloginService.cs
1using System.Net.Http.Headers;
2using System.Text;
3using System.Text.Json;
4
5namespace MyApp.Services;
6
7public class TuraloginService
8{
9 private readonly HttpClient _httpClient;
10 private readonly string _apiKey;
11 private readonly string _validationUrl;
12 private const string BaseUrl = "https://api.turalogin.com/api/v1";
13
14 public TuraloginService(HttpClient httpClient, IConfiguration config)
15 {
16 _httpClient = httpClient;
17 _apiKey = config["Turalogin:ApiKey"]
18 ?? throw new ArgumentNullException("Turalogin API key not configured");
19 _validationUrl = config["Turalogin:ValidationUrl"]
20 ?? throw new ArgumentNullException("Turalogin validation URL not configured");
21
22 _httpClient.DefaultRequestHeaders.Authorization =
23 new AuthenticationHeaderValue("Bearer", _apiKey);
24 }
25
26 public async Task StartAuthAsync(string email)
27 {
28 await PostAsync("/auth/start", new {
29 email,
30 validationUrl = _validationUrl // Where the magic link redirects to
31 });
32 }
33
34 public async Task<AuthResult> VerifyTokenAsync(string token)
35 {
36 var response = await PostAsync("/auth/verify", new { sessionId = token });
37
38 var userElement = response.GetProperty("user");
39 return new AuthResult(
40 Token: response.GetProperty("token").GetString()!,
41 User: new TuraloginUser(
42 Id: userElement.GetProperty("id").GetString()!,
43 Email: userElement.GetProperty("email").GetString()!
44 )
45 );
46 }
47
48 private async Task<JsonElement> PostAsync(string endpoint, object data)
49 {
50 var json = JsonSerializer.Serialize(data);
51 var content = new StringContent(json, Encoding.UTF8, "application/json");
52
53 var response = await _httpClient.PostAsync($"{BaseUrl}{endpoint}", content);
54 var responseBody = await response.Content.ReadAsStringAsync();
55 var result = JsonDocument.Parse(responseBody).RootElement;
56
57 if (!response.IsSuccessStatusCode)
58 {
59 var error = result.TryGetProperty("error", out var e)
60 ? e.GetString()
61 : "Unknown error";
62 var code = result.TryGetProperty("code", out var c)
63 ? c.GetString()
64 : "UNKNOWN";
65
66 throw new TuraloginException(error!, code!, (int)response.StatusCode);
67 }
68
69 return result;
70 }
71}
72
73public record AuthResult(string Token, TuraloginUser User);
74public record TuraloginUser(string Id, string Email);

5. Exception Class

Custom exception for Turalogin-related errors.

Exceptions/TuraloginException.cs
1namespace MyApp.Exceptions;
2
3public class TuraloginException : Exception
4{
5 public string ErrorCode { get; }
6 public int StatusCode { get; }
7
8 public TuraloginException(string message, string code, int status)
9 : base(message)
10 {
11 ErrorCode = code;
12 StatusCode = status;
13 }
14}

6. Error Handling Middleware

Middleware to handle Turalogin exceptions globally.

Middleware/TuraloginExceptionMiddleware.cs
1using System.Text.Json;
2using MyApp.Exceptions;
3
4namespace MyApp.Middleware;
5
6public class TuraloginExceptionMiddleware
7{
8 private readonly RequestDelegate _next;
9 private readonly ILogger<TuraloginExceptionMiddleware> _logger;
10
11 public TuraloginExceptionMiddleware(
12 RequestDelegate next,
13 ILogger<TuraloginExceptionMiddleware> logger)
14 {
15 _next = next;
16 _logger = logger;
17 }
18
19 public async Task InvokeAsync(HttpContext context)
20 {
21 try
22 {
23 await _next(context);
24 }
25 catch (TuraloginException ex)
26 {
27 _logger.LogWarning(
28 "Turalogin error: {Message} ({Code})",
29 ex.Message,
30 ex.ErrorCode
31 );
32
33 var message = ex.ErrorCode switch
34 {
35 "INVALID_EMAIL" => "Please provide a valid email address.",
36 "SESSION_EXPIRED" => "Login link has expired. Please try again.",
37 "INVALID_TOKEN" => "Invalid login link.",
38 "RATE_LIMITED" => "Too many attempts. Please wait a moment.",
39 _ => "Authentication error. Please try again."
40 };
41
42 context.Response.StatusCode = ex.StatusCode;
43 context.Response.ContentType = "application/json";
44
45 await context.Response.WriteAsync(JsonSerializer.Serialize(new
46 {
47 error = message,
48 code = ex.ErrorCode
49 }));
50 }
51 }
52}
53
54// Extension method
55public static class TuraloginExceptionMiddlewareExtensions
56{
57 public static IApplicationBuilder UseTuraloginExceptionHandler(
58 this IApplicationBuilder builder)
59 {
60 return builder.UseMiddleware<TuraloginExceptionMiddleware>();
61 }
62}

Complete ASP.NET Core Application

Complete Program.cs setup with magic link authentication.

Program.cs
1using Microsoft.AspNetCore.Authentication.Cookies;
2using MyApp.Services;
3using MyApp.Middleware;
4
5var builder = WebApplication.CreateBuilder(args);
6
7// Add services
8builder.Services.AddControllers();
9builder.Services.AddHttpClient<TuraloginService>();
10
11// Configure authentication
12builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
13 .AddCookie(options =>
14 {
15 options.Cookie.HttpOnly = true;
16 options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
17 options.Cookie.SameSite = SameSiteMode.Lax;
18 options.ExpireTimeSpan = TimeSpan.FromDays(7);
19 options.SlidingExpiration = true;
20 options.Events.OnRedirectToLogin = context =>
21 {
22 context.Response.StatusCode = StatusCodes.Status401Unauthorized;
23 return Task.CompletedTask;
24 };
25 });
26
27builder.Services.AddAuthorization();
28
29// CORS (if needed)
30builder.Services.AddCors(options =>
31{
32 options.AddDefaultPolicy(policy =>
33 {
34 policy.WithOrigins(builder.Configuration["FrontendUrl"]!)
35 .AllowCredentials()
36 .AllowAnyMethod()
37 .AllowAnyHeader();
38 });
39});
40
41var app = builder.Build();
42
43// Middleware pipeline
44app.UseCors();
45app.UseTuraloginExceptionHandler();
46app.UseAuthentication();
47app.UseAuthorization();
48app.MapControllers();
49
50app.Run();
51
52// appsettings.json
53/*
54{
55 "Turalogin": {
56 "ApiKey": "your-api-key-here",
57 "ValidationUrl": "http://localhost:5000/auth/callback"
58 },
59 "FrontendUrl": "http://localhost:3000"
60}
61*/
62
63// Protected endpoint example
64[ApiController]
65[Route("api")]
66[Authorize]
67public class ApiController : ControllerBase
68{
69 [HttpGet("me")]
70 public IActionResult GetMe()
71 {
72 return Ok(new
73 {
74 id = User.FindFirst(ClaimTypes.NameIdentifier)?.Value,
75 email = User.FindFirst(ClaimTypes.Email)?.Value
76 });
77 }
78
79 [HttpGet("dashboard")]
80 public IActionResult Dashboard()
81 {
82 var email = User.FindFirst(ClaimTypes.Email)?.Value;
83 return Ok(new { message = $"Welcome to the dashboard, {email}!" });
84 }
85}

Ready to integrate?

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