diff --git a/docs/index.rst b/docs/index.rst index 273c959de..f6587511f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -80,6 +80,7 @@ Open.IdentityServer enables the following features in your applications: topics/compatibility topics/resources topics/clients + topics/server_side_sessions topics/signin topics/signin_external_providers topics/windows diff --git a/docs/migrating/from_duende.rst b/docs/migrating/from_duende.rst index 6a9f7b64d..90e4a7d75 100644 --- a/docs/migrating/from_duende.rst +++ b/docs/migrating/from_duende.rst @@ -71,8 +71,6 @@ Migration Steps - Remove all references. Not yet supported in Open.IdentityServer. * - Automatic Key Management - Remove all references. You will need to configure signing keys manually, or :ref:`configure read-only key store `. - * - Server Side Sessions - - Remove all references. Not yet supported in Open.IdentityServer. * - Pushed Authorisation Requests (PAR) - Remove all references. Not yet supported in Open.IdentityServer. * - CIBA (Client Initiated Backchannel Authentication) diff --git a/docs/reference/options.rst b/docs/reference/options.rst index 040115b8d..a3bdbe8cf 100644 --- a/docs/reference/options.rst +++ b/docs/reference/options.rst @@ -155,3 +155,24 @@ Mutual TLS Specifies whether a cnf claim gets emitted for access tokens if a client certificate was present. Normally the cnf claims only gets emitted if the client used the client certificate for authentication, setting this to true, will set the claim regardless of the authentication method. (defaults to false). + +Server-Side Sessions +^^^^^^^^^^^^^^^^^^^^ + +* ``ExpiredSessionsTriggerBackchannelLogout`` + Specifies if session expiry should trigger back channel logout, this will override any other settings that may + cause back channel logout such as AuthenticationOptions.CoordinateClientLifetimesWithUserSession or + Client.CoordinateLifetimeWithUserSession. + +* ``RemoveExpiredSessions`` + Specifies if expired sessions should be cleaned up automatically by Open.IdentityServer. The default value is true. + +* ``RemoveExpiredSessionsFrequency`` + Specifies the frequency with which expired sessions are looked for and removed. The default value is a TimeSpan of 10 minutes. + +* ``FuzzExpiredSessionsFrequency`` + Specifies if the start time of the hosted service should be randomised. This avoids the scenario where multiple running instances + of identityserver run cleanup jobs simultaneously. The default value is true. + +* ``RemoveExpiredSessionsBatchSize`` + Specifies how many expired sessions should be removed in a single pass. The default value is 100. diff --git a/docs/topics/server_side_sessions.rst b/docs/topics/server_side_sessions.rst new file mode 100644 index 000000000..bca7b8914 --- /dev/null +++ b/docs/topics/server_side_sessions.rst @@ -0,0 +1,225 @@ +.. _refServerSideSessions: + +Server-Side Sessions +==================== + +Overview +-------- +When users authenticate with Open.IdentityServer, a session is created to track the logged in user. By default this will be done by storing this state in cookies in the user browser. This approach of storing session state in a cookie can work well for many scenarios but does have some drawbacks. + +* **No Tracking Active Sessions** - There is no way to track active sessions, and how many users are currently logged in. +* **No Immediate Revocation** - There will be no process of Immediate session revocation on the server side-session cookie will be valid till it expires, or they log out. +* **No Sign-Out Coordination** - Coordinating sign-outs from Open.IdentityServer with connected clients is less relable without server tracking of active sessions. + +Open.IdentityServer Server-Side Sessions solves these issues by storing the contents of this cookie in a server side data store. This gives Open.IdentityServer the ability to: + +* Provide APIs for managing and querying active user sessions +* Support for explicit session revocation regardless of the cookie state in the browser +* Storing session data server side, so browser cookie only contains an ID for the session nothing more + +Getting Started +^^^^^^^^^^^^^^^ + +1. **Database schema** + + Ensure your database is in the correct state. If you are coming from Duende IdentityServer, there is nothing further to do - the schema is already compatible. If you are migrating from IdentityServer4 and have not yet updated your schema to match the Open.IdentityServer schema, you will need to do this first. See :ref:`migration from IdentityServer4 ` for details. + +2. **Enable server-side sessions** + + Call ``.AddServerSideSessions()`` when configuring Open.IdentityServer: + + .. code-block:: csharp + + builder.Services.AddIdentityServer() + .AddServerSideSessions(); + +3. **Configure a session store** + + ``AddServerSideSessions`` requires an implementation of ``IServerSideSessionStore`` to persist session data. If you are using Entity Framework Core, this is provided automatically when you configure the operational store: + + .. code-block:: csharp + + builder.Services.AddIdentityServer() + .AddServerSideSessions() + .AddOperationalStore(options => + { + options.ConfigureDbContext = b => + b.UseSqlServer("ConnectionString"); + }); + + If you are not using the built-in EF Core store, you will need to provide your own ``IServerSideSessionStore`` implementation. + +5. **(Optional) Configure additional session options** + + You can customize behavior via ``ServerSideSessionOptions``, such as how often sessions are checked for expiration in the background, or coordinating this with your sign-in cookie expiration: + + .. code-block:: csharp + + builder.Services.AddIdentityServer(options => + { + // Other options... + options.ServerSideSessions.ExpiredSessionsTriggerBackchannelLogout = true; + options.ServerSideSessions.RemoveExpiredSessions = true; + options.ServerSideSessions.RemoveExpiredSessionsFrequency = TimeSpan.FromSeconds(10); + options.ServerSideSessions.FuzzExpiredSessionsFrequency = true; + options.ServerSideSessions.RemoveExpiredSessionsBatchSize = 100; + }); + +Management Interface +^^^^^^^^^^^^^^^^^^^^ + +Open.IdentityServer has a built-in session management interface, ``ISessionManagementService``, that allows you to query existing sessions and remove sessions. When you configure Open.IdentityServer to use server-side sessions, a default implementation is registered for this interface. + +The interface provides two methods: + +- ``Task> ISessionManagementService.QuerySessionsAsync(SessionQuery? filter, CancellationToken ct = default)`` + + Filters sessions using the ``SessionQuery`` object. The filter is optional; default values are used when it is not provided. + +- ``Task ISessionManagementService.RemoveSessionsAsync(RemoveSessionsContext context, CancellationToken ct = default)`` + + Removes sessions using the ``RemoveSessionsContext`` object. The context allows you to control which sessions are removed and what actions are taken as part of the removal. + +Data Types +^^^^^^^^^^ + +The following types are used by ``ISessionManagementService`` to query and manage sessions. + +SessionQuery +"""""""""""" + +``SessionQuery`` is used to filter results when calling ``QuerySessionsAsync``. + +.. list-table:: + :header-rows: 1 + :widths: 30 20 50 + + * - Property + - Type + - Description + * - ``ResultsToken`` + - ``string?`` + - Optional selector for current page location, contains identifier for the first element and last element in page of results. e.g. '0,24' + * - ``RequestPriorResults`` + - ``bool`` + - Specifies if instead of getting next page should get the previous page that ResultsToken identifies. Only valid if ResultsToken is specified. + * - ``CountRequested`` + - ``int`` + - Specifies the count requested per page, defaults to 25 + * - ``SubjectId`` + - ``string?`` + - Filters sessions with a specific subject id + * - ``SessionId`` + - ``string?`` + - Filters sessions with a specific session id + * - ``DisplayName`` + - ``string?`` + - Filters sessions with a specific display name + +QueryResult +"""""""""""""" + +``QueryResult`` wraps paged results returned from ``QuerySessionsAsync``. + +.. list-table:: + :header-rows: 1 + :widths: 30 20 50 + + * - Property + - Type + - Description + * - ``ResultsToken`` + - ``string?`` + - Token identifying the current page of results. Contains the first element and last element in page of results. e.g. '0,24' + * - ``HasPrevResults`` + - ``bool`` + - Specifies if there is a page of results before this page + * - ``HasNextResults`` + - ``bool`` + - Specifies if there is a page of results after this page + * - ``TotalCount`` + - ``int?`` + - Total sessions accross all pages of results + * - ``TotalPages`` + - ``int?`` + - Total number of pages for query result + * - ``CurrentPage`` + - ``int?`` + - Page numer of the current result collection + * - ``Results`` + - ``IReadOnlyCollection`` + - The collection of results for the current page + +UserSession +""""""""""" + +``UserSession`` represents a single server-side session record. + +.. list-table:: + :header-rows: 1 + :widths: 30 20 50 + + * - Property + - Type + - Description + * - ``SubjectId`` + - ``string`` + - The subject (user) identifier associated with the session. + * - ``SessionId`` + - ``string`` + - The unique identifier for the session + * - ``DisplayName`` + - ``string?`` + - An optional display name for the user + * - ``Created`` + - ``DateTime`` + - The date and time the session was created. + * - ``Renewed`` + - ``DateTime`` + - The date and time the session was last renewed + * - ``Expires`` + - ``DateTime?`` + - The date and time the session expires, if applicable + * - ``Issuer`` + - ``string?`` + - The issuer of the authentication ticket + * - ``Clients`` + - ``IEnumerable`` + - The clients associated with the session + * - ``AuthenticationTicket`` + - ``AuthenticationTicket?`` + - The user sessions suthentication ticket object + +RemoveSessionsContext +"""""""""""""""""""""" + +``RemoveSessionsContext`` controls which sessions are removed and what side effects occur when calling ``RemoveSessionsAsync``. + +.. list-table:: + :header-rows: 1 + :widths: 30 20 50 + + * - Property + - Type + - Description + * - ``SubjectId`` + - ``string?`` + - Optional if SessionId has value, limits removal to a specific subject id + * - ``SessionId`` + - ``string?`` + - Optional if SubjectId has value, limits removal to a specific session id + * - ``ClientIds`` + - ``IEnumerable?`` + - Optionally limits removal to sessions for specific clients + * - ``RemoveServerSideSession`` + - ``bool`` + - Whether to trigger session entity removal from the database + * - ``SendBackchannelLogoutNotification`` + - ``bool`` + - Whether to trigger backchannel logout notifications for removed sessions + * - ``RevokeTokens`` + - ``bool`` + - Whether to trigger session token removal + * - ``RevokeConsents`` + - ``bool`` + - Whether to trigger session consent removal \ No newline at end of file