Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 0 additions & 108 deletions src/content/docs/bff/extensibility/sessions.md

This file was deleted.

183 changes: 183 additions & 0 deletions src/content/docs/bff/extensibility/sessions.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
---
title: "Session Management"
description: Configure and implement custom server-side session storage and lifecycle management through IUserSessionStore interface
date: 2020-09-10T08:22:12+02:00
sidebar:
label: "Session Management"
order: 20
redirect_from:
- /bff/v2/extensibility/sessions/
- /bff/v3/extensibility/sessions/
- /identityserver/v5/bff/extensibility/sessions/
- /identityserver/v6/bff/extensibility/sessions/
- /identityserver/v7/bff/extensibility/sessions/
---
import { Badge } from "@astrojs/starlight/components";
import { Code } from "@astrojs/starlight/components";
import { Tabs, TabItem } from "@astrojs/starlight/components";

Server-side sessions enable secure and efficient storage of session data, allowing flexibility through custom
implementations of the `IUserSessionStore` interface. This ensures adaptability to various storage solutions tailored to
your application's needs.

## User Session Store

If using the server-side sessions feature, you will need to have a store for the session data.
An Entity Framework Core based implementation of this store is provided.

If you wish to use some other type of store, can implement the `IUserSessionStore` interface:

{/* prettier-ignore */}
<Tabs syncKey="bffVersion">
{/* prettier-ignore */}
<TabItem label="Duende BFF v4">
```csharp
/// <summary>
/// User session store
/// </summary>
public interface IUserSessionStore
{
/// <summary>
/// Retrieves a user session
/// </summary>
/// <param name="key"></param>
/// <param name="ct">A token that can be used to request cancellation of the asynchronous operation.</param>
/// <returns></returns>
Task<UserSession?> GetUserSessionAsync(UserSessionKey key, CT ct = default);

/// <summary>
/// Creates a user session
/// </summary>
/// <param name="session"></param>
/// <param name="ct">A token that can be used to request cancellation of the asynchronous operation.</param>
/// <returns></returns>
Task CreateUserSessionAsync(UserSession session, CT ct = default);

/// <summary>
/// Updates a user session
/// </summary>
/// <param name="key"></param>
/// <param name="session"></param>
/// <param name="ct">A token that can be used to request cancellation of the asynchronous operation.</param>
/// <returns></returns>
Task UpdateUserSessionAsync(UserSessionKey key, UserSessionUpdate session, CT ct = default);

/// <summary>
/// Deletes a user session
/// </summary>
/// <param name="key"></param>
/// <param name="ct">A token that can be used to request cancellation of the asynchronous operation.</param>
/// <returns></returns>
Task DeleteUserSessionAsync(UserSessionKey key, CT ct = default);

/// <summary>
/// Queries user sessions based on the filter.
/// </summary>
/// <param name="partitionKey">The partition key to use</param>
/// <param name="filter"></param>
/// <param name="ct">A token that can be used to request cancellation of the asynchronous operation.</param>
/// <returns></returns>
Task<IReadOnlyCollection<UserSession>> GetUserSessionsAsync(PartitionKey partitionKey, UserSessionsFilter filter, CT ct = default);

/// <summary>
/// Deletes user sessions based on the filter.
/// </summary>
/// <param name="partitionKey">The partition key</param>
/// <param name="filter"></param>
/// <param name="ct">A token that can be used to request cancellation of the asynchronous operation.</param>
/// <returns></returns>
Task DeleteUserSessionsAsync(PartitionKey partitionKey, UserSessionsFilter filter, CT ct = default);
}
```

:::caution[Do not store `UserSession` directly]
Your `IUserSessionStore` implementation is expected to implement custom code to roundtrip the data from the user session to the underlying storage mechanism.
You should not rely on existing serializers, such as `System.Text.Json` or `Newtonsoft.Json`, to serialize the `UserSession` object.
:::
</TabItem>

{/* prettier-ignore */}
<TabItem label="Duende BFF v3">
```csharp
/// <summary>
/// User session store
/// </summary>
public interface IUserSessionStore
{
/// <summary>
/// Retrieves a user session
/// </summary>
/// <param name="key"></param>
/// <param name="cancellationToken">A token that can be used to request cancellation of the asynchronous operation.</param>
/// <returns></returns>
Task<UserSession?> GetUserSessionAsync(string key, CancellationToken cancellationToken = default);

/// <summary>
/// Creates a user session
/// </summary>
/// <param name="session"></param>
/// <param name="cancellationToken">A token that can be used to request cancellation of the asynchronous operation.</param>
/// <returns></returns>
Task CreateUserSessionAsync(UserSession session, CancellationToken cancellationToken = default);

/// <summary>
/// Updates a user session
/// </summary>
/// <param name="key"></param>
/// <param name="session"></param>
/// <param name="cancellationToken">A token that can be used to request cancellation of the asynchronous operation.</param>
/// <returns></returns>
Task UpdateUserSessionAsync(string key, UserSessionUpdate session, CancellationToken cancellationToken = default);

/// <summary>
/// Deletes a user session
/// </summary>
/// <param name="key"></param>
/// <param name="cancellationToken">A token that can be used to request cancellation of the asynchronous operation.</param>
/// <returns></returns>
Task DeleteUserSessionAsync(string key, CancellationToken cancellationToken = default);

/// <summary>
/// Queries user sessions based on the filter.
/// </summary>
/// <param name="filter"></param>
/// <param name="cancellationToken">A token that can be used to request cancellation of the asynchronous operation.</param>
/// <returns></returns>
Task<IReadOnlyCollection<UserSession>> GetUserSessionsAsync(UserSessionsFilter filter, CancellationToken cancellationToken = default);

/// <summary>
/// Deletes user sessions based on the filter.
/// </summary>
/// <param name="filter"></param>
/// <param name="cancellationToken">A token that can be used to request cancellation of the asynchronous operation.</param>
/// <returns></returns>
Task DeleteUserSessionsAsync(UserSessionsFilter filter, CancellationToken cancellationToken = default);
}
```
</TabItem>
</Tabs>

Once you have an implementation, you can register it when you enable server-side sessions:

```csharp
// Program.cs
builder.Services.AddBff()
.AddServerSideSessions<YourStoreClassName>();
```

## User Session Store Cleanup

The `IUserSessionStoreCleanup` interface is used to model cleaning up expired sessions.

```csharp
/// <summary>
/// User session store cleanup
/// </summary>
public interface IUserSessionStoreCleanup
{
/// <summary>
/// Deletes expired sessions
/// </summary>
Task DeleteExpiredSessionsAsync(CancellationToken cancellationToken = default);
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ builder.Services.AddBff()
.AddServerSideSessions();
```

The default implementation stores the session in-memory. This is useful for testing, but for production you typically want a more robust storage mechanism. We provide an implementation of the session store built with EntityFramework (EF) that can be used with any database with an EF provider (e.g. Microsoft SQL Server). You can also use a custom store. See [extensibility](/bff/extensibility/sessions.md#user-session-store) for more information.
The default implementation stores the session in-memory. This is useful for testing, but for production you typically want a more robust storage mechanism. We provide an implementation of the session store built with EntityFramework (EF) that can be used with any database with an EF provider (e.g. Microsoft SQL Server). You can also use a custom store. See [extensibility](/bff/extensibility/sessions.mdx#user-session-store) for more information.

## Using Entity Framework for the Server-Side Session Store

Expand Down