January 12, 2026 | By Hiro Protagonist, Hacker / Metaverse Architect
The problem with systems—complex, distributed, massive systems that span the breadth of the Metaverse—is that they suffer from a fundamental epistemological deficiency: they don't know how to talk to strangers.
You build a server. It’s a beautiful thing, a crystalline lattice of logic and endpoints, sitting there on the fiber-optic highway like a zen garden of data. It supports the Model Context Protocol (MCP), which is the new lingua franca for AI agents, a way for digital intelligences to exchange tools and resources without getting bogged down in the messy wetware semantics of natural language. But then a client comes along—a wandering Ronin of a CLI, or perhaps a heavy industrial AI construct looking for tools to automate a process—and it hits a wall.
The wall is authentication.
In the old days, you’d just hardcode it. You’d pass a shared secret in a back-alley handshake, a grimy string of alphanumeric characters labeled API_KEY that lived in a .env file and got accidentally committed to GitHub repositories where it would be scraped by bots and used to mine crypto until your AWS bill looked like the GDP of a small island nation. It was crude. It was effective. It was the digital equivalent of a secret knock.
But we live in a civilized age, or at least we aspire to. We use OAuth 2.0. We use OpenID Connect. We have authorization servers and token endpoints and intricate dances of redirects and callbacks that ensure identity is verified, scopes are granted, and access is revoked when necessary. It’s a bureaucracy, yes, but it’s a bureaucracy that prevents the entire structure from collapsing into anarchy.
The issue, however, remains: how does the client know?
How does an MCP client, stumbling upon your server in the vast dark of the network, know where to send the user to log in? How does it know which issuer to trust? How does it know that you demand the openid and roles scopes, but don't care a whit about offline_access?
Usually, you write documentation. You write a README. You expect the developer to read it. This is a fatal error in judgment. Developers do not read. They scan. They grep. They paste.
The solution, as is often the case in computer science, is a layer of indirection that describes the layer of direction. Enter RFC 9728, also known as "OAuth 2.0 Protected Resource Metadata."
It’s a deceptively simple standard. It says: "Hey, if you get a 401 Unauthorized, I’m going to send you a header or a JSON blob that tells you exactly who my boss is."
The Authority: The AI Platform Dashboard
In the AI Platform—formerly a simple job automation tool, now evolved into a piece of infrastructure designed to let AI agents navigate the labyrinthine bureaucracy of modern employment—we architected the "Authority" using OpenIddict. This isn't just a database of users; it's the gatekeeper of the realm.
We configured the Dashboard to support both the standard Authorization Code flow (for browsers) and the Device Code flow (for those Ronin CLIs living in the terminal).
// Inside the Dashboard's Program.cs
builder.Services.AddOpenIddict()
.AddServer(options =>
{
// The endpoints where the handshake happens
options.SetAuthorizationEndpointUris("/connect/authorize")
.SetDeviceAuthorizationEndpointUris("/connect/device")
.SetTokenEndpointUris("/connect/token")
.SetEndUserVerificationEndpointUris("/device/verify");
// We allow both browser-based and terminal-based flows
options.AllowAuthorizationCodeFlow()
.AllowDeviceAuthorizationFlow();
// The badges we issue
options.RegisterScopes(
OpenIddictConstants.Scopes.OpenId,
OpenIddictConstants.Scopes.Email,
OpenIddictConstants.Scopes.Profile,
OpenIddictConstants.Scopes.Roles);
// ... crypto configuration omitted for brevity ...
});
When a client like gemini-cli connects, it doesn't need to guess these endpoints. It discovers them because the Resource Server (the MCP Server) tells it exactly where to look.
The Resource: The MCP Server
The MCP Server is the vault. It holds the tools—the resume parsers, the job applicators, the semantic memory vectors. It doesn't care who you are, as long as the Authority says you're cool.
We implemented the discovery mechanism using ModelContextProtocol.AspNetCore. The configuration is where the art happens. It succinct. It’s declarative. It tells the world: "I am the AI Platform MCP Server. I answer to the Authority at ai.devlin.vining.club. If you want to talk to me, bring a badge that says you have these scopes."
// Inside the MCP Server's Program.cs
.AddMcp(options =>
{
// Configure Protected Resource Metadata (RFC 9728) for OAuth discovery
options.ResourceMetadata = new()
{
AuthorizationServers = { new Uri("https://ai.devlin.vining.club/") },
ScopesSupported = ["openid", "email", "profile", "roles"],
ResourceName = "AI Platform MCP Server",
};
});
The Hybrid Protocol: Pragmatism over Purity
But because we are pragmatists—because sometimes you just need to get the job done and you don’t have time to spin up a browser for a full interactive login flow, or you're a legacy script running in a basement server rack—we also support the old ways. We support the API Key.
We utilize a ForwardDefaultSelector in the authentication builder, a piece of middleware logic that acts like a bouncer at the door of a club. It looks at the Authorization header. Does it start with mcp_sk_? If so, you’re on the guest list; go right in to the ApiKey handler. If not? Well, then you better have a JWT signed by the Authority, or you’re going to get bounced to the OpenIddict validation scheme.
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = "ApiKey";
options.DefaultChallengeScheme = McpAuthenticationDefaults.AuthenticationScheme;
})
.AddPolicyScheme("ApiKey", "API Key or OAuth", options =>
{
options.ForwardDefaultSelector = context =>
{
var authHeader = context.Request.Headers.Authorization.ToString();
// The secret knock
if (!string.IsNullOrEmpty(authHeader) && authHeader.Contains("mcp_sk_"))
{
return ApiKeyAuthenticationHandler.SchemeName;
}
// The official badge
return OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
};
});
This hybrid approach is the Metaverse in microcosm: high-protocol civilization resting atop a foundation of pragmatic hacks.
We expose the metadata at /.well-known/oauth-protected-resource. When a sophisticated client hits the server and gets a 401, it checks this endpoint. It sees the authorization_server URL. It initiates the Device Flow. It prints a code to your terminal: User code: QKJL-BMNQ. You authenticate on your phone. The client gets the token.
The connection is established. The tools are unlocked. The job automation begins.
It makes the system discoverable. It makes it browsable. It turns an opaque black box into a self-describing artifact. And in a world drowning in information but starving for context, a system that can explain itself is the only kind of system worth building.
Transmission archived by Hiro Protagonist. Technical stack includes ASP.NET Core 10, OpenIddict, ModelContextProtocol, and enough caffeine to kill a small horse.