Skip to main content

Integrate authentication into ASP.NET

This guide shows how to create a simple ASP.NET application and secure it with authentication powered by Ory. You can use this guide with both Ory Network and self-hosted Ory software.

This guide is perfect for you if:

  1. You have .NET installed.
  2. You want to build an app using ASP.NET.
  3. You want to give access to your application to signed-in users only.
info

You can find the code of the sample application here.

Install Ory CLI

Follow this guide to install the Ory CLI on your machine.

Why do I Need the Ory CLI?

Ory CLI provides a convenient way to configure and manage projects. Additionally, the CLI contains Ory Tunnel, which exposes Ory APIs under the same top-level domain as your application to ensure that there are no CORS issues. This allows the application that runs on your machine to connect to Ory APIs.

Ory Tunnel

Create ASP.NET app

Create an empty web template as a starting point for this example. Run these commands:

mkdir your-project
cd your-project

dotnet new web

Install Ory SDK

Run this command to install the Ory SDK:

dotnet add package Ory.Client

Configure the SDK

Add the Ory Client to the template app. Make the following changes to the Program.cs file:

Program.cs
using Ory.Client.Api;
using Ory.Client.Client;

var builder = WebApplication.CreateBuilder(args);

// configure http port explicitly to override generated settings from launchSettings.json
builder.WebHost.ConfigureKestrel(opt => {
var port = builder.Configuration.GetValue<int>("APP_PORT", 5001);
opt.ListenAnyIP(port);
});

var app = builder.Build();

// create a new Ory Client with the BasePath set to the Ory Tunnel enpoint
var oryBasePath = builder.Configuration.GetValue<string>("ORY_BASEPATH") ?? "http://localhost:4000";
var ory = new FrontendApi(new Configuration
{
BasePath = oryBasePath
});

app.MapGet("/", () => "Hello World!");

app.Run();

Validate and login

Next, create middleware that checks if the user has a valid session. The session is considered valid when the user is authenticated.

The middleware passes the request cookies to the Ory Client to check if the session is valid.

If the session is valid, the user is presented with the protected page. When the session is not valid, which means that the user is not authenticated or the session expired, the request is redirected for login using the Ory Account Experience.

Program.cs
using Ory.Client.Api;
using Ory.Client.Client;

var builder = WebApplication.CreateBuilder(args);

// configure http port explicitly to override generated settings from launchSettings.json
builder.WebHost.ConfigureKestrel(opt => {
var port = builder.Configuration.GetValue<int>("APP_PORT", 5001);
opt.ListenAnyIP(port);
});

var app = builder.Build();

// create a new Ory Client with the BasePath set to the Ory Tunnel enpoint
var oryBasePath = builder.Configuration.GetValue<string>("ORY_BASEPATH") ?? "http://localhost:4000";
var ory = new FrontendApi(new Configuration
{
BasePath = oryBasePath
});

// add session middleware
app.Use(async (ctx, next) =>
{
async Task Login()
{
// this will redirect the user to the managed Ory Login UI
var flow = await ory.CreateBrowserLoginFlowAsync() ?? throw new InvalidOperationException("Could not create browser login flow");
ctx.Response.Redirect(flow.RequestUrl);
}

try
{
// check if we have a session
var session = await ory.ToSessionAsync(cookie: ctx.Request.Headers.Cookie, cancellationToken: ctx.RequestAborted);
if (session?.Active is not true)
{
await Login();
return;
}

// add session to HttpContext
ctx.Items["req.session"] = session;
}
catch (ApiException)
{
await Login();
return;
}

await next(ctx);
});

app.MapGet("/", () => "Hello World!");

app.Run();

The protected page

  1. Create the Index RazorPage page that shows session data to users with a valid session.

    dotnet new page --name Index --no-pagemodel --output Pages
  2. Add this code to the Pages/Index.cshtml file to present the data to the user:

    Pages/Index.cshtml
    @page
    @{
    // try to retrieve session from HttpContext
    var session = HttpContext.Items.TryGetValue("req.session", out var item) && item is Ory.Client.Model.ClientSession s ? s.ToJson() : "<NO SESSION>";
    }

    <html lang="en">
    <head>
    <title>Ory Network secured ASP.NET Core web app</title>
    </head>
    <body>
    <h1>Dashboard</h1>
    <hr />
    <h2>Your Session Data:</h2>
    <pre><code>@session</code></pre>
    </body>
    </html>

Configure application

To configure the app to serve RazorPages, make the following changes in Program.cs. Make sure to replace the app.MapGet("/", () => "Hello World!"); line with app.MapRazorPages();.

Program.cs
using Ory.Client.Api;
using Ory.Client.Client;

var builder = WebApplication.CreateBuilder(args);

// configure http port explicitly to override generated settings from launchSettings.json
builder.WebHost.ConfigureKestrel(opt => {
var port = builder.Configuration.GetValue<int>("APP_PORT", 5001);
opt.ListenAnyIP(port);
});

// add support for RazorPages
builder.Services.AddRazorPages();

var app = builder.Build();

// create a new Ory Client with the BasePath set to the Ory Tunnel enpoint
var oryBasePath = builder.Configuration.GetValue<string>("ORY_BASEPATH") ?? "http://localhost:4000";
var ory = new FrontendApi(new Configuration
{
BasePath = oryBasePath
});

// add session middleware
app.Use(async (ctx, next) =>
{
async Task Login()
{
// this will redirect the user to the managed Ory Login UI
var flow = await ory.CreateBrowserLoginFlowAsync() ?? throw new InvalidOperationException("Could not create browser login flow");
ctx.Response.Redirect(flow.RequestUrl);
}

try
{
// check if we have a session
var session = await ory.ToSessionAsync(cookie: ctx.Request.Headers.Cookie, cancellationToken: ctx.RequestAborted);
if (session?.Active is not true)
{
await Login();
return;
}

// add session to HttpContext
ctx.Items["req.session"] = session;
}
catch (ApiException)
{
await Login();
return;
}

await next(ctx);
});

// configure pipeline to use RazorPages
app.MapRazorPages();
app.MapGet("/", () => "Hello World!");

app.Run();

Test your application

With all of the pieces in place, it's time to test your application. Follow these steps:

  1. Start the application:

    dotnet run
  2. Run Ory Tunnel to mirror the Ory API endpoints on your application's domain (localhost):

    ory tunnel --project playground --dev http://localhost:5001
  3. Open localhost:5001 to access the application. As the initial call is made by an unauthenticated user, the middleware doesn't detect a valid session and redirects to the login page of the defined Ory project.

  4. From there, you can create a new account or sign in using an existing identity. When you sign in, the session becomes valid and the application shows the Index page with the session data.

tip

To see a more advanced example of integrating Ory with ASP.NET Core check out the examples repository.

Go to production

You can use many different approaches to go to production with your application. You can deploy it on Kubernetes, AWS, a VM, a RaspberryPi - the choice is yours! To connect the application to your Ory project, the app and Ory APIs must be available under the same common domain, for example https://ory.example.com and https://www.example.com.

You can easily connect Ory to your subdomain. To do that, add a Custom Domain to your Ory Network project.

With the custom domain set up, you don't need to use Ory Proxy or Ory Tunnel to interact with Ory APIs. Instead, use the configured custom domain in your SDK calls:

// register a new Ory client with the URL set to the custom domain
var ory = new FrontendApi(new Configuration
{
BasePath = "https://ory.example.org"
});