Skip to main content

Posts

Reducing the size of your authentication cookie with ITicketStore

We are currently testing a new WAF for our organization. After activating it, we noticed that some requests never hit our server. Further investigation showed that the root cause was linked to our authentication cookies becoming to big. As the WAF had very strict limits configured, the request was blocked. The cause is how cookie authentication in ASP.NET Core works by default. The complete AuthenticationTicket (the claims, the properties and the tokens) is serialized, encrypted and put in the cookie. The bigger your identity, the bigger your cookie. Of course, we could just change the WAF configuration and increase the limits but isn't there a better way that allows us to limit the cookie size? Let's find out together... Keep the ticket on the server Cookie authentication has an extension point for this: ITicketStore . When you provide an implementation through CookieAuthenticationOptions.SessionStore , the ticket is stored server-side. The cookie only contains a se...

Napkin math: know what your system should do before you measure it

Last week I was evaluating some application performance characteristics with another architect. Our gut feeling told us that the numbers didn't make sense but we couldn't pinpoint why we had this feeling. This reminded me of a recent Pragmatic Engineer podcast episode with Simon Eskildsen (co-founder of turbopuffer, ex-Shopify). He was talking about a habit that fixes exactly this: napkin math . What is napkin math? Napkin math means estimating how a system should perform, using a few known numbers and some arithmetic. No code, no prototype, no load test. You work from first principles: how fast can this machine read memory, how long does a round trip to S3 take, what does a gigabyte cost? Simon turned this into a project. He collected the real numbers for latency, bandwidth and cost and kept them in a table on GitHub . Then he made flashcards for almost every cell, so he could recall them instantly during a design review. That is a key point: he didn’t look the numb...

Using the ADFS userinfo endpoint instead of allatclaims

In my previous post I used the allatclaims scope to get all claims in the ID token. That works, but there’s a catch: every claim you add makes the token bigger. With a lot of group memberships, the token grows quickly, and it gets sent along with every request that carries it. The alternative is to keep the ID token small and ask ADFS for the extra claims when you need them. That’s what the userinfo endpoint is for. How does it work? The userinfo endpoint is part of the OpenID Connect standard. Your application sends the access token as a bearer token, and ADFS returns the claims for that user as JSON. In ADFS the endpoint lives here: https://<adfs-server>/adfs/userinfo You can find it in the discovery document as well: https://<adfs-server>/adfs/.well-known/openid-configuration There is one important detail. ADFS treats userinfo as a resource of its own, with the identifier urn:microsoft:userinfo . The access token you send to the endpoint must be issued ...

Getting all your claims in the ID token with the ADFS allatclaims scope

Recently I ran into a puzzling issue while connecting an application to ADFS using its built-in OpenID Connect support. The login worked fine, the user got authenticated, but the ID token contained almost nothing I needed. No group claims, no custom attributes, just the basics. The claim rules were configured correctly. So where were my claims? Where did my claims go? ADFS keeps a strict separation between the two tokens. The claims you define through the issuance transform rules end up in the access token. The ID token gets a much smaller set by default. If your application reads the ID token to get user information, you have two options: Call the userinfo endpoint with the access token Ask ADFS to copy the access token claims into the ID token This is where the allatclaims scope comes in. What does allatclaims do? When the authorization request includes scope=allatclaims , ADFS customizes the ID token so it includes the claims from the access token, based on ...

Getting visual explanations from your coding agent with the show-me skill

Coding agents are good at explaining things. They are also good at explaining them in five verbose paragraphs when a ten-line tree would have done the job. You would almost think that output tokens are free! Recently I came across the show-me skill from HumanLayer . It’s a small skill with one purpose: when you ask your agent to explain something, it answers with a visual representation instead of a wall of text. What does it do? The whole skill is a short set of instructions. It tells the agent to skip the preamble, keep the prose brief and pick the smallest view that makes the point clear. Sounds simple? Because the idea is indeed. For each kind of explanation, the skill names the view to use: Logic or an algorithm → pseudocode Runtime control flow → a call tree UI structure → a component tree, including the state and module boundaries that matter File responsibility or a broad refactor → a shallow file tree Component interaction or data flow → a Me...

Using FileLifecycleHooks in Serilog

In my post yesterday, I showed how to configure rolling and retention so a runaway log file no longer fills your disk. That solves the problem, but it leaves a question open: what if you want to do something with those files before they disappear? Note: This post is a follow-up on Cleaning up old log files with Serilog . Maybe you want to compress the files to save space. Maybe compliance requires you to archive them first. Serilog.Sinks.File has an extension point for this: FileLifecycleHooks . What are FileLifecycleHooks? A lifecycle hook lets you run your own code at specific moments in the life of a log file. You inherit from the abstract class FileLifecycleHooks and override one or both of these methods: OnFileOpened : called when the sink opens a new log file. You receive the underlying stream and can return your own stream that wraps it. OnFileDeleting : called just before a file is deleted by the retention policy. Both have a default implementation that do...

Cleaning up old log files with Serilog

We got an alert from our ops team: the disk of one of our servers was filling up. The culprit was a log file that grew so fast it ate all the available space. The dev team didn't configured any cleanup, so the file just kept growing. The application was already using Serilog . Let's have a look what options we have available to limit the amount of log data. The default config The simplest way to write a log file with Serilog looks like this: Log.Logger = new LoggerConfiguration() .WriteTo.File("logs/log.txt") .CreateLogger(); This works, but it writes everything to one single file. By default, no rolling happens and nothing gets deleted. Remark: This isn’t entirely true. The file sink has a default fileSizeLimitBytes of 1 GB. When the file reaches that limit, Serilog silently stops writing log events. So you don’t fill your disk, but you lose your logs. That’s not much better. Rolling files The first step is to start a new file at regular int...

Tuning the default logging providers in ASP.NET Core through configuration

After deploying a new application to production, we noticed that a lot of extra log messages where written to the EventLog. As we didn't configure the EventLog logging provider in our application, we did not expect this. Turns out that when you create a new ASP.NET Core application with WebApplication.CreateBuilder , you get a set of logging providers activated out-of-the-box. So the question becomes: which providers are enabled, and how do you get rid of the ones you don’t need? Which providers are enabled by default? The default builder registers the following providers: Console Debug EventSource EventLog (Windows only) You can verify this yourself by looking at the registered ILoggerProvider services: var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); var providers = app.Services.GetServices<ILoggerProvider>(); foreach (var provider in providers) { Console.WriteLine(provider.GetType().Name); } On Windows this pr...

Getting started with DSC 3.0 – Part 6: Using the DSC MCP server with your AI coding tools

Throughout this series I ran into the same kind of problem again and again. Which resource type do I need? What is the exact name and casing of a property? Which adapter runs it? Names also change between versions. The Windows PowerShell adapter got a new name in 3.2, and the dsc mcp command became dsc server in 3.3. An AI assistant that writes DSC YAML for you can easily get this wrong. It guesses, based on what it saw during training. DSC 3.0 has a built-in answer for that: an MCP server that lets the assistant ask DSC itself. Note: this post is part of a bigger series on Microsoft Desired State Configuration. Getting started with DSC 3.0 – Part 1: What is DSC and what changed? Getting started with DSC 3.0 – Part 2: Managing a Windows service end to end Getting started with DSC 3.0 – Part 3: Capturing the current state with dsc config export Getting started with DSC 3.0 – Part 4: Configuring IIS with multiple resources and dependsOn Getting started with DSC 3.0 – Part 5: Guard...

Getting started with DSC 3.0 – Part 5: Guarding your configuration with Assertion

At the end of the previous post I said that dependsOn only decides the order in which resources are processed. It doesn't check that the resource you depend on is actually in the desired state. Sometimes that's not enough. You want to say "only touch this machine if it's Windows Server 2025", or "only configure the website if IIS is really installed". That's what the Microsoft.DSC/Assertion resource is for. Note: this post is part of a bigger series on Microsoft Desired State Configuration. Getting started with DSC 3.0 – Part 1: What is DSC and what changed? Getting started with DSC 3.0 – Part 2: Managing a Windows service end to end Getting started with DSC 3.0 – Part 3: Capturing the current state with dsc config export Getting started with DSC 3.0 – Part 4: Configuring IIS with multiple resources and dependsOn Getting started with DSC 3.0 – Part 5: Guarding your configuration with Assertion (this post) What is an assertion? An assertio...

Getting started with DSC 3.0 – Part 4: Configuring IIS with multiple resources and dependsOn

Until now we configured one resource at a time. A real server needs several, and they depend on each other. You can't create a website before IIS is installed, and you can't attach a web application to a website that doesn't exist yet. In this post we set up IIS, an application pool, a website and a web application in a single configuration document, and use dependsOn to control the order. Note: this post is part of a bigger series on Microsoft Desired State Configuration. Getting started with DSC 3.0 – Part 1: What is DSC and what changed? Getting started with DSC 3.0 – Part 2: Managing a Windows service end to end Getting started with DSC 3.0 – Part 3: Capturing the current state with dsc config export Getting started with DSC 3.0 – Part 4: Configuring IIS with multiple resources and dependsOn (this post) What we are building Six resource instances, with these dependencies: IIS (Windows feature): no dependencies Site folder and App f...

Getting started with DSC 3.0 – Part 3: Capturing the current state with dsc config export

In the previous post we wrote a configuration document for a single service by hand. That works when you know exactly what you want to manage. But what if you inherit a machine and have no idea what's configured on it? Or you have one server that works fine and you want the others to look the same? Writing the document from scratch is slow and you will forget things. That's what dsc config export is for. Note: this post is part of a bigger series on Microsoft Desired State Configuration. Getting started with DSC 3.0 – Part 1: What is DSC and what changed? Getting started with DSC 3.0 – Part 2: Managing a Windows service end to end Getting started with DSC 3.0 – Part 3: Capturing the current state with dsc config export (this post) What does export do? The export command inspects the system and generates a configuration document that contains every instance of the resources you ask for. The result is a normal configuration document, so you can use it ...

Getting started with DSC 3.0 – Part 2: Managing a Windows service end to end

In the previous post we looked at what DSC is and what changed in 3.0. Time to put it to work. A Windows service is a good first example. It's something most teams have, and it's easy to break without anybody noticing. Someone sets the start type to Manual while troubleshooting, forgets to put it back, and a few weeks later the service doesn't come up after a reboot. Let's use DSC to describe the state we want and keep it that way. Note: this post is part of a bigger series on Microsoft Desired State Configuration: Getting started with DSC 3.0 – Part 1: What is DSC and what changed? Getting started with DSC 3.0 – Part 2: Managing a Windows service end to end (this post) What you need DSC v3.3 or later, because Microsoft.Windows/Service was added in that release A Windows machine An elevated terminal for the set operation Check your version first: dsc --version Remark: the resource can only manage services that are already regis...