<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://avneeshk.me/feed/by_tag/identity.xml" rel="self" type="application/atom+xml" /><link href="https://avneeshk.me/" rel="alternate" type="text/html" hreflang="en" /><updated>2026-10-18T06:23:53+00:00</updated><id>https://avneeshk.me/feed/by_tag/identity.xml</id><title type="html">Avneesh Kasture</title><subtitle>Building secure MCP servers for clients — hardening the agentic layer against prompt injection, tool misuse, and privilege abuse. Field notes on MCP security, agentic safety, and shipping AI platforms.</subtitle><author><name>Avneesh Kasture</name><email>apkasture02@gmail.com</email></author><entry><title type="html">The user signed in twice. Was it the same user both times?</title><link href="https://avneeshk.me/blog/two-logins-two-identities/" rel="alternate" type="text/html" title="The user signed in twice. Was it the same user both times?" /><published>2026-10-18T05:20:00+00:00</published><updated>2026-10-18T05:20:00+00:00</updated><id>https://avneeshk.me/blog/two-logins-two-identities</id><content type="html" xml:base="https://avneeshk.me/blog/two-logins-two-identities/"><![CDATA[<p>Suppose an agent acts on a downstream API for the user. The user signs in to
your identity provider, so you know who they are. Then the agent runs an OAuth
flow against the downstream API, so it has a token to act with. Every action
goes into an audit log under the identity from the first step:
“alice@example.com refunded order 4471.”</p>

<p>Is that log line true?</p>

<p>Only if the downstream’s single sign-on is federated to your identity provider.
Without federation, the user signed in twice to two unrelated accounts, and the
log can name the wrong person.</p>

<p>Okay, so what does federation do here? The second login doesn’t use a
downstream password. The downstream sends the user back to your identity
provider, which already knows it’s Alice, and Alice’s account at the downstream
is the one that gets the token. Your Conditional Access and MFA policies apply
to that sign-in too, as long as they
<a href="https://learn.microsoft.com/en-us/entra/identity/conditional-access/concept-conditional-access-cloud-apps">target the downstream app</a>
or all resources. The identity you verified is the identity that acts.</p>

<p>Now take federation away. The second login is a separate login, and the user
types whatever credentials they like into the downstream’s own sign-in page.
Maybe they’re Alice’s. Maybe Alice is signed in to the downstream in that
browser as the shared support account, or as her personal account, or as Bob,
because Bob was using the laptop yesterday. Both tokens are real. Nothing in
the flow connects them. You verified one person in step one and got a token for
some account in step two.</p>

<p>A token proves that some account authorized the agent to act. It doesn’t say
which human was at the keyboard, and it says nothing at all about any other
token. Federation is what links the two.</p>

<p>The reason federation is missing is often mundane. The downstream account is on
a plan that doesn’t offer SSO, so there’s nothing to federate.</p>

<p>Now, you might say, “So the log is a little loose. Alice was still the one who
signed in.” Let’s run the usual check. Who is the attacker? Anyone who completes
the downstream login with an account other than Alice’s, which includes Bob from
yesterday and doesn’t require any malice. Who is the victim? Alice, whose name
is on the refund, and whoever reads the log later. What did the attacker gain?
No new access, since they already held those downstream credentials. They
gained a log that credits their actions to someone else.</p>

<p>The audit log exists to answer one question, usually under pressure: who did
this? This one looks complete and well-formed, and it points at the wrong
person. That’s worse than having no log, because people will believe this one.</p>

<p>So don’t write “the downstream is federated to your identity provider” in a
design doc until you’ve seen the SSO configuration on the downstream side.
Check that the customer’s plan supports SSO at all, because many plans don’t.
Check that SSO is required, not just available: Slack, for example, lets an
admin make it
<a href="https://slack.com/help/articles/203772216-SAML-single-sign-on">required, partially required or optional</a>,
and lets workspace owners bypass it with an email and password. Then it’s one
of these cases.</p>

<ul>
  <li><strong>Federation is there.</strong> Keep both legs. You get your access policies on the
downstream and one verified person across the whole chain.</li>
  <li><strong>Federation isn’t there, and the deployment is single-user or local.</strong> Drop
your identity-provider leg. Ask the downstream who the token belongs to,
through its <code class="language-plaintext highlighter-rouge">userinfo</code> endpoint or equivalent, and record that. The identity
in the log is then the identity that acted. Don’t make the user sign in twice
to establish a connection you can’t establish.</li>
  <li><strong>Federation isn’t there, and you need multi-user accountability.</strong> Then you
need federation, or you record both identities and stop claiming they’re the
same person: “alice@example.com (signed in), acting as support@vendor
(downstream token).”</li>
</ul>

<p><strong>Exercise:</strong> You check the <code class="language-plaintext highlighter-rouge">userinfo</code> response from the downstream after the
second login, and its <code class="language-plaintext highlighter-rouge">email</code> field matches the email your identity provider
returned: both say <code class="language-plaintext highlighter-rouge">alice@example.com</code>. Doesn’t that prove the two logins were
the same person?</p>

<details class="post-answer">
  <summary>Show an answer</summary>
  
<p>No. It proves that two accounts in two separate systems have the same email string.</p>

<p>Without federation, each system decided on its own who <code class="language-plaintext highlighter-rouge">alice@example.com</code> is. The downstream might let users set their own email, or not verify it. The account might be a shared one that someone registered with Alice’s address years ago. Nobody proved to both systems that it was the same person.</p>

<p>Email matching is fine as a hint to show a human (“these look like the same person, confirm?”). It doesn’t belong in an audit log as fact. The comparison that holds up is a stable identifier that one system vouches for to the other, which is what federation provides: the downstream account is linked to the identity provider’s subject, and the downstream sent the user to your identity provider to sign in.</p>

</details>]]></content><author><name>Avneesh Kasture</name><email>apkasture02@gmail.com</email></author><category term="mcp" /><category term="identity" /><category term="oauth" /><summary type="html"><![CDATA[The two-leg auth pattern (your identity provider for who the user is, OAuth for the downstream API) only describes one person when the downstream's SSO is federated to that identity provider. Without federation the two logins are to two unrelated accounts, and the audit log can name the wrong person. How to check, and what to build when federation isn't there.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://avneeshk.me/assets/og/two-logins-two-identities.png" /><media:content medium="image" url="https://avneeshk.me/assets/og/two-logins-two-identities.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>