diff --git a/docs/pages/docs/features/security/oauth2/installation/index.md b/docs/pages/docs/features/security/oauth2/installation/index.md
index 7b072a2548cb12c1e551b36afa865bf8d6182e99..5ad2874563c725f97f485a4fd02cc105561e75ba 100644
--- a/docs/pages/docs/features/security/oauth2/installation/index.md
+++ b/docs/pages/docs/features/security/oauth2/installation/index.md
@@ -103,3 +103,31 @@ $ php ./bin/resonance.php generate:defuse-key > oauth2/defuse.key
 ```
 
 Then, change the CHMOD permissions for that key to `0600`.
+
+## Post Session Authentication Hook
+
+If you are using {{tutorials/session-based-authentication/index}} you need
+to return `OAuth2UserSessionAuthenticated` instance
+from your authentication {{docs/features/http/responders}} (see also:
+{{docs/features/http/interceptors}}).
+
+It allows OAuth2 to know that the user is authenticated and that it should
+check if user is in the middle of OAuth2 flow.
+
+```php
+<?php
+
+use Distantmagic\Resonance\OAuth2UserSessionAuthenticated;
+
+final readonly class LoginValidation extends HttpController
+{
+    public function createResponse(): HttpInterceptableInterface 
+    {
+        // ...
+        // perform session authentication somehow
+        // ...
+
+        return new OAuth2UserSessionAuthenticated();
+    }
+}
+```
diff --git a/resources/css/docs-hljs.css b/resources/css/docs-hljs.css
index f9fafeb9cc86bd6e31aca9831f06be0c35b0a679..ff3a8f727cb8c3c3ae972d5f8bae812415cc7161 100644
--- a/resources/css/docs-hljs.css
+++ b/resources/css/docs-hljs.css
@@ -85,6 +85,7 @@ code[class] {
 .fenced-code {
   background-color: var(--color-block-background);
   box-shadow: 8px 8px #00000033;
+  margin: 20px 0;
 
   @media screen and (min-width: 1024px) {
     position: relative;
diff --git a/src/HttpResponder/OAuth2/PostSessionAuthentication.php b/src/HttpInterceptor/OAuth2UserSessionAuthenticatedInterceptor.php
similarity index 69%
rename from src/HttpResponder/OAuth2/PostSessionAuthentication.php
rename to src/HttpInterceptor/OAuth2UserSessionAuthenticatedInterceptor.php
index 5579045b7ce61b11ecb5e57f58e2f222ce6ac0e7..8db3569731953fc911f98f6ebf5709231d007892 100644
--- a/src/HttpResponder/OAuth2/PostSessionAuthentication.php
+++ b/src/HttpInterceptor/OAuth2UserSessionAuthenticatedInterceptor.php
@@ -2,25 +2,32 @@
 
 declare(strict_types=1);
 
-namespace Distantmagic\Resonance\HttpResponder\OAuth2;
+namespace Distantmagic\Resonance\HttpInterceptor;
 
 use Distantmagic\Resonance\Attribute\GrantsFeature;
+use Distantmagic\Resonance\Attribute\Intercepts;
 use Distantmagic\Resonance\Attribute\Singleton;
 use Distantmagic\Resonance\Feature;
 use Distantmagic\Resonance\HttpInterceptableInterface;
-use Distantmagic\Resonance\HttpResponder;
+use Distantmagic\Resonance\HttpInterceptor;
 use Distantmagic\Resonance\HttpResponderInterface;
 use Distantmagic\Resonance\OAuth2AuthorizationCodeFlowControllerInterface;
 use Distantmagic\Resonance\OAuth2AuthorizationRequestSessionStore;
 use Distantmagic\Resonance\OAuth2AuthorizedUser;
+use Distantmagic\Resonance\OAuth2UserSessionAuthenticated;
 use Distantmagic\Resonance\SessionAuthentication;
+use Distantmagic\Resonance\SingletonCollection;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use RuntimeException;
 
+/**
+ * @template-extends HttpInterceptor<OAuth2UserSessionAuthenticated>
+ */
 #[GrantsFeature(Feature::OAuth2)]
-#[Singleton]
-final readonly class PostSessionAuthentication extends HttpResponder
+#[Intercepts(OAuth2UserSessionAuthenticated::class)]
+#[Singleton(collection: SingletonCollection::HttpInterceptor)]
+final readonly class OAuth2UserSessionAuthenticatedInterceptor extends HttpInterceptor
 {
     public function __construct(
         private OAuth2AuthorizationCodeFlowControllerInterface $authorizationCodeFlowController,
@@ -28,8 +35,11 @@ final readonly class PostSessionAuthentication extends HttpResponder
         private SessionAuthentication $sessionAuthentication,
     ) {}
 
-    public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpInterceptableInterface|HttpResponderInterface|ResponseInterface
-    {
+    public function intercept(
+        ServerRequestInterface $request,
+        ResponseInterface $response,
+        object $intercepted,
+    ): HttpInterceptableInterface|HttpResponderInterface|ResponseInterface {
         if (!$this->authorizationRequestSessionStore->has($request)) {
             return $this->authorizationCodeFlowController->redirectToAuthenticatedPage($request, $response);
         }
diff --git a/src/OAuth2UserSessionAuthenticated.php b/src/OAuth2UserSessionAuthenticated.php
new file mode 100644
index 0000000000000000000000000000000000000000..998d33b8d5c2bab42dbfd64d79ad8967a1782e85
--- /dev/null
+++ b/src/OAuth2UserSessionAuthenticated.php
@@ -0,0 +1,36 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Distantmagic\Resonance;
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+
+final readonly class OAuth2UserSessionAuthenticated implements HttpInterceptableInterface
+{
+    private SwooleContextRequestResponseReader $swooleContextRequestResponseReader;
+
+    /**
+     * @psalm-taint-source file $templatePath
+     */
+    public function __construct(
+        ?ServerRequestInterface $request = null,
+        ?ResponseInterface $response = null,
+    ) {
+        $this->swooleContextRequestResponseReader = new SwooleContextRequestResponseReader(
+            request: $request,
+            response: $response,
+        );
+    }
+
+    public function getResponse(): ResponseInterface
+    {
+        return $this->swooleContextRequestResponseReader->getResponse();
+    }
+
+    public function getServerRequest(): ServerRequestInterface
+    {
+        return $this->swooleContextRequestResponseReader->getServerRequest();
+    }
+}