Skip to main content

4 posts tagged with "oidc"

View all tags
intermediatePart 6

The wrong valid token: authenticating an MCP tools server with authentik

· 16 min read
Rafael Fernandes
NLP Engineer & Tech Writer at WiLine
Share:
authentik+Model Context Protocol

Part 5 gave an agent its own identity at the gateway: a token issued by authentik over client credentials, carrying a scope, expiring in five minutes. It ended by naming what it had not covered — the MCP tools server from agent orchestration part 4 still trusts anything that can reach its port, issue_refund included.

That post was explicit about the limit of what it had built:

The MCP server still trusts everyone. Scoping happens in the client. Anything that can reach 127.0.0.1:8770 can call issue_refund directly, agent or not.

Splitting the toolbox per role stopped an agent from reaching a tool it shouldn't. It did nothing about a curl. This part closes that.

intermediatePart 5

The key that expires: giving an agent its own identity at the gateway

· 19 min read
Rafael Fernandes
NLP Engineer & Tech Writer at WiLine
Share:
authentik+LiteLLM

Part 4 put group access control on the gateway's admin UI and then, at the end, called the API from a shell with no account, no session and no group. It answered normally. The conclusion was that SSO protects a control plane and the data plane authenticates machine callers with keys — which it has to, because an agent running at 3am cannot complete a browser login.

That was true and it was also a stopping point rather than an answer. "Machine callers use keys" leaves you with a credential that never expires, that no identity provider knows about, and that survives the person who created it. Part 4 said so plainly: removing someone from a group does not revoke their keys, a leaked key is unaffected by identity entirely, and keys outlive people.

This part gives the machine an identity instead of a key.

authentik issues the agent a token over the client credentials grant — no browser, no consent screen, no human. The token is signed, carries a scope, and expires in five minutes. The gateway verifies it locally against authentik's public keys and refuses anything without the right scope. At the end, three status codes show the boundary holding.

intermediatePart 4

The binding that wasn't there: group access control, and what SSO doesn't protect

· 16 min read
Rafael Fernandes
NLP Engineer & Tech Writer at WiLine
Share:
authentik+LiteLLM

Part 3 put authentik in front of Langfuse and ended with an admission: the bindings step was left empty, so every account in authentik could reach Langfuse and nothing would warn you.

This part closes that gap on the LiteLLM gateway — and the closing went wrong in a way worth more than the procedure. We configured the bindings in authentik's wizard, watched them appear in the wizard's own table, submitted, and ended up with zero bindings saved. The application was open to everyone, the UI said nothing, and the only reason we found out is that we tested with an account that should have been refused and wasn't.

Then, once access control genuinely worked, we called the gateway's API from a shell with no account, no session and no group. It answered normally. That one isn't a bug — it's the difference between a control plane and a data plane, and assuming SSO covers both is how people conclude they've secured something they haven't.

intermediatePart 3

One login for everything: putting authentik in front of a self-hosted app

· 20 min read
Rafael Fernandes
NLP Engineer & Tech Writer at WiLine
Share:
authentik+

Part 1 closed the ports nobody meant to open. Part 2 stopped two containers from running as root. Both were about the machine. Neither touched the question a self-hosted AI stack answers worst: who is allowed to log in, and where is that decided?

Same box as before. The Langfuse we've been hardening since Part 1 — the one whose Postgres, ClickHouse and Redis Part 1 found correctly bound to localhost, and whose worker Part 2 dropped off root — was deployed back in Catch what your tests miss. Two parts have now secured the machine underneath it without once touching the application's own front door. This is the first part that changes Langfuse itself.

Right now that decision is made in each app, separately. Langfuse has its own email-and- password table. So does every other tool on the box. Each one is a place where an account can outlive the person who owned it, where a password can be reused, and where "remove this person's access" means remembering that the app exists at all.

This post moves that decision to one place. That place is authentik — an open-source identity provider you run yourself, the self-hosted counterpart to Okta or Auth0. It holds the accounts, runs the login screen, and vouches for who someone is to any app that asks. Apps stop storing passwords and start asking authentik.

It's the same job Keycloak does, and Keycloak is the better-known name. authentik earns the pick here on setup cost: a compose file and a wizard against Keycloak's realms, clients and JVM tuning. For one box and one app, that difference is the whole decision.

We deploy it, connect Langfuse to it over OIDC, and end with a login that goes through authentik and back.