<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Auth Log Bundle</title>
        <link>https://spiriitlabs.github.io/auth-log-bundle/</link>
        <description>Release announcements for the Symfony Auth Log Bundle.</description>
        <lastBuildDate>Thu, 03 Sep 2026 09:01:23 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en-US</language>
        <image>
            <title>Auth Log Bundle</title>
            <url>https://spiriitlabs.github.io/auth-log-bundle/og-image.png</url>
            <link>https://spiriitlabs.github.io/auth-log-bundle/</link>
        </image>
        <copyright>Copyright © 2026 Spiriit</copyright>
        <atom:link href="https://spiriitlabs.github.io/auth-log-bundle/feed.xml" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Auth Log Bundle 4.0: “It wasn't me” now does something]]></title>
            <link>https://spiriitlabs.github.io/auth-log-bundle/news/auth-log-bundle-4-0</link>
            <guid isPermaLink="false">https://spiriitlabs.github.io/auth-log-bundle/news/auth-log-bundle-4-0</guid>
            <pubDate>Wed, 02 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Disavowing a login now revokes the attacker's known contexts, can end every session and force a password reset — automatically, the moment the user reports it.]]></description>
            <content:encoded><![CDATA[<h1 id="auth-log-bundle-4-0-it-wasn-t-me-now-does-something" tabindex="-1">Auth Log Bundle 4.0: “It wasn't me” now does something <a class="header-anchor" href="#auth-log-bundle-4-0-it-wasn-t-me-now-does-something" aria-label="Permalink to “Auth Log Bundle 4.0: “It wasn't me” now does something”">&#8203;</a></h1>
<p><strong>Starting with 4.0, disavowing a login is no longer just an event you have to handle. The bundle revokes the user's known contexts on the spot, and can end every session and force a password reset — with your own reactions running alongside.</strong></p>
<h2 id="a-warning-that-only-warns-is-half-a-security-control" tabindex="-1">A warning that only warns is half a security control <a class="header-anchor" href="#a-warning-that-only-warns-is-half-a-security-control" aria-label="Permalink to “A warning that only warns is half a security control”">&#8203;</a></h2>
<p>Picture the alert landing at 2am. Unknown device, unknown city. The user taps <strong>“It wasn't me”</strong>, and then?</p>
<p>The attacker's session is still open. Their IP address is now a <em>known context</em> — recorded, trusted, silent. Their next sign-in raises no alert at all. The user did everything right and nothing happened.</p>
<p>4.0 closes that window.</p>
<h2 id="three-reactions-one-line-of-config-each" tabindex="-1">Three reactions, one line of config each <a class="header-anchor" href="#three-reactions-one-line-of-config-each" aria-label="Permalink to “Three reactions, one line of config each”">&#8203;</a></h2>
<div class="language-yaml"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">yaml</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#11782a;--shiki-dark:#85E89D">spiriit_auth_log</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">:</span></span>
<span class="line"><span style="--shiki-light:#11782a;--shiki-dark:#85E89D">    confirmation</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">:</span></span>
<span class="line"><span style="--shiki-light:#11782a;--shiki-dark:#85E89D">        enabled</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">true</span></span>
<span class="line"><span style="--shiki-light:#11782a;--shiki-dark:#85E89D">        on_disavowal</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">:</span></span>
<span class="line"><span style="--shiki-light:#11782a;--shiki-dark:#85E89D">            revoke_known_contexts</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">true</span><span style="--shiki-light:#62687b;--shiki-dark:#818e99">    # default</span></span>
<span class="line"><span style="--shiki-light:#11782a;--shiki-dark:#85E89D">            invalidate_sessions</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">false</span><span style="--shiki-light:#62687b;--shiki-dark:#818e99">     # opt-in</span></span>
<span class="line"><span style="--shiki-light:#11782a;--shiki-dark:#85E89D">            force_password_reset</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">false</span><span style="--shiki-light:#62687b;--shiki-dark:#818e99">    # opt-in</span></span></code></pre>
</div><div class="reaction-cards">
  <div class="reaction-card">
    <div class="reaction-card-head">
      <code class="reaction-card-name">revoke_known_contexts</code>
      <span class="reaction-card-badge is-default">On by default</span>
    </div>
    <p class="reaction-card-text">Untrusts every known context, so the attacker's next login raises a fresh alert.</p>
    <p class="reaction-card-port">Port to implement <code>RevocableAuthenticationLogRepositoryInterface</code></p>
  </div>
  <div class="reaction-card">
    <div class="reaction-card-head">
      <code class="reaction-card-name">invalidate_sessions</code>
      <span class="reaction-card-badge">Opt-in</span>
    </div>
    <p class="reaction-card-text">Signs the account out everywhere.</p>
    <p class="reaction-card-port">Port to implement <code>SessionInvalidatorInterface</code></p>
  </div>
  <div class="reaction-card">
    <div class="reaction-card-head">
      <code class="reaction-card-name">force_password_reset</code>
      <span class="reaction-card-badge">Opt-in</span>
    </div>
    <p class="reaction-card-text">Sends the user through your account recovery flow.</p>
    <p class="reaction-card-port">Port to implement <code>PasswordResetRequesterInterface</code></p>
  </div>
</div>
<p>Revocation is on by default because it repairs the flaw that makes a disavowal dangerous in the first place. The other two are opt-in: they touch your session storage and your recovery flow, and no bundle can guess those.</p>
<p>Each reaction delegates its sensitive half to a small interface — a <em>port</em> — that your application implements. Write the class, and autoconfiguration wires it.</p>
<p>Enable a reaction whose port has no implementation and <strong>container compilation fails</strong>, naming the interface to write. A security measure that silently does nothing is worse than a build error.</p>
<h2 id="bring-your-own-reaction" tabindex="-1">Bring your own reaction <a class="header-anchor" href="#bring-your-own-reaction" aria-label="Permalink to “Bring your own reaction”">&#8203;</a></h2>
<p>Notify your SOC, revoke API tokens, quarantine the account, page someone. One class:</p>
<div class="language-php"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">php</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583">final</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583"> class</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> NotifySecurityTeam</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583"> implements</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> DisavowalReactionInterface</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">{</span></span>
<span class="line"><span style="--shiki-light:#c62739;--shiki-dark:#F97583">    public</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583"> function</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> react</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">DisavowedLogin</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> $disavowedLogin)</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583">:</span><span style="--shiki-light:#c62739;--shiki-dark:#F97583"> void</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    {</span></span>
<span class="line"><span style="--shiki-light:#62687b;--shiki-dark:#818e99">        // $disavowedLogin->user, ->userIdentity, ->authenticationLog</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    }</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
</div><p>It runs with the built-ins, before <code>LOGIN_DISAVOWED</code> is dispatched.</p>
<h2 id="your-logs-now-remember-who-they-were-written-for" tabindex="-1">Your logs now remember who they were written for <a class="header-anchor" href="#your-logs-now-remember-who-they-were-written-for" aria-label="Permalink to “Your logs now remember who they were written for”">&#8203;</a></h2>
<p>A log is a journal: it must remember, not ask again. <code>AbstractAuthenticationLog</code> records the user identifier it was written with, next to the user class.</p>
<p>Two things follow. Checking whether a context is known no longer reloads the User entity — <strong>one query less on every single login</strong>. And a log keeps telling the truth about who signed in, even after the account row changes underneath it.</p>
<p>This one needs a schema migration and a back-fill. The <a href="https://spiriitlabs.github.io/auth-log-bundle/upgrade/4.0">upgrade guide</a> covers both, including logs pointing at deleted users.</p>
<h2 id="get-started" tabindex="-1">Get started <a class="header-anchor" href="#get-started" aria-label="Permalink to “Get started”">&#8203;</a></h2>
<div class="language-bash"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">composer</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> require</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> spiriitlabs/auth-log-bundle:^4.0</span></span></code></pre>
</div><p>PHP 8.2+, Symfony 6.4, 7.4 and 8.0, Doctrine ORM 3 or 4.</p>
<p>New here? Start with <a href="https://spiriitlabs.github.io/auth-log-bundle/features/disavowal-reactions">disavowal reactions</a>. Already running the bundle? The <a href="https://spiriitlabs.github.io/auth-log-bundle/upgrade/4.0">upgrade guide</a> is a ten-minute read and tells you exactly what your repository owes the new version.</p>
]]></content:encoded>
            <author>Spiriit</author>
        </item>
        <item>
            <title><![CDATA[Who logged in as you?]]></title>
            <link>https://spiriitlabs.github.io/auth-log-bundle/news/who-logged-in-as-you</link>
            <guid isPermaLink="false">https://spiriitlabs.github.io/auth-log-bundle/news/who-logged-in-as-you</guid>
            <pubDate>Mon, 31 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[A stolen password is not the failure. What your application does in the minutes after someone says “That wasn't me” — that is the part you control.]]></description>
            <content:encoded><![CDATA[<h1 id="who-logged-in-as-you" tabindex="-1">Who logged in as you? <a class="header-anchor" href="#who-logged-in-as-you" aria-label="Permalink to “Who logged in as you?”">&#8203;</a></h1>
<p>Do you know who logged into your application last week? From where? On which device?</p>
<p>And more importantly: what happens when the user says <strong>“That wasn't me”</strong>?</p>
<p>That's often where it ends.</p>
<p>The numbers say the rest. The median intruder goes <strong>14 days</strong> before anyone notices, and barely half of intrusions — <strong>52 %</strong> — are caught by the organization itself, <a href="https://cloud.google.com/blog/topics/threat-intelligence/m-trends-2026" target="_blank" rel="noreferrer">Mandiant reports</a>. Everyone else finds out from a third party, or from a ransom note.</p>
<p>The password may have been stolen somewhere else. It usually was: credential abuse still turns up somewhere in <strong>39 % of breaches</strong>, and half of ransomware victims had credentials leaked in the <strong>95 days</strong> before the attack — <a href="https://www.verizon.com/about/news/breach-industry-wide-dbir-finds" target="_blank" rel="noreferrer">Verizon's 2026 DBIR</a>.</p>
<p>What your application can control is what happens next.</p>
<p>New IP address, new device, new location: notify the user.</p>
<p><strong>“That was me” / “That wasn't me”</strong></p>
<p>And if it wasn't them, take action: close sessions, revoke access, require a password change, raise an alert.</p>
<p>Speed is the whole game. Stolen access now changes hands <strong>22 seconds</strong> after the initial compromise — it was more than eight hours in 2022. And breaches that run past 200 days cost about <strong>a third more</strong> than the ones closed sooner.</p>
<p>That's exactly what <strong>Auth Log Bundle</strong> is for: logging authentication attempts, detecting unusual contexts, and <a href="https://spiriitlabs.github.io/auth-log-bundle/features/disavowal-reactions">reacting when a login is disputed</a>.</p>
<div class="language-bash"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">composer</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> require</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> spiriitlabs/auth-log-bundle</span></span></code></pre>
</div><p>The question isn't whether an account will ever be compromised.</p>
<p>It's <strong>what you'll do when it happens.</strong></p>
<hr>
<p><em>Sources: <a href="https://cloud.google.com/blog/topics/threat-intelligence/m-trends-2026" target="_blank" rel="noreferrer">Mandiant M-Trends 2026</a> · <a href="https://www.verizon.com/business/resources/reports/dbir/" target="_blank" rel="noreferrer">Verizon DBIR 2026</a> · <a href="https://www.ibm.com/reports/data-breach" target="_blank" rel="noreferrer">IBM Cost of a Data Breach 2026</a></em></p>
]]></content:encoded>
            <author>Spiriit</author>
        </item>
    </channel>
</rss>