Skip to Content
Course content

118: Working with Environment Variables and Configuration

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've seen it happen a dozen times: a junior developer pushes a project to GitHub, and within ten minutes, they get an email from a security bot telling them their AWS secret key or SendGrid API token has been leaked. It's a rite of passage, but it's one we can easily avoid. The root of the problem is usually the same—treating configuration as part of the code rather than as part of the environment.

The Hardcoded Trap and the Git Leak

When you're first hacking together a prototype, it's tempting to just drop your API key right into a string. It's fast, and it works. You might write something like this:

public class WeatherService 
{
    private const string ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; // Quick and easy, right?

    public async Task GetForecast() 
    {
        var client = new HttpClient();
        var response = await client.GetAsync($"https://api.weather.com/v3/forecast?key={ApiKey}");
        // ...
    }
}

Here is where it breaks. First, if you need to change that key—say, switching from a sandbox account to a production account—you have to recompile and redeploy the entire application. Second, and more importantly, that key is now forever etched into your version control history. Even if you delete the line in a later commit, the key is still there in the Git history for anyone to find. You've essentially handed the keys to your house to anyone who can see your repository.

Moving to Config Files, but Not Solving Everything

The next step most developers take is moving those strings into an appsettings.json file. This is better because it separates the "what" from the "how." You're using the .NET IConfiguration system, which is the gold standard for C# apps.

// appsettings.json
{
  "WeatherApi": {
    "ApiKey": "sk_test_4eC39HqLyjWDarjtT1zdp7dc",
    "BaseUrl": "https://api.weather.com/v3/"
  }
}

In your code, you'd inject IConfiguration and pull the value out: _config["WeatherApi:ApiKey"]. This feels professional, and it allows you to have different files for different environments (like appsettings.Development.json). But we still have a problem: someone is eventually going to forget to add appsettings.json to the .gitignore file, and we're right back to the "Git Leak" nightmare.

Decoupling Secrets via Environment Variables

The real "pro" move is to treat appsettings.json as a place for non-sensitive defaults (like the API Base URL) and use Environment Variables for the actual secrets. Environment variables live on the machine running the code, not in the code itself. This means your production server has the real key, your local machine has a test key, and neither is ever committed to Git.

The beauty of .NET is that the ConfigurationBuilder can stack these sources. It reads the JSON file first, and then it reads the environment variables. If a variable exists in both places, the environment variable wins. I always set it up this way because it gives me the best of both worlds: a readable config file for structure, and secure overrides for secrets.

// In your Program.cs or Host setup
var builder = Host.CreateApplicationBuilder(args);

// .NET does this by default in most templates, but here is the logic:
builder.Configuration
    .AddJsonFile("appsettings.json", optional: true)
    .AddEnvironmentVariables(); 

var apiKey = builder.Configuration["WeatherApi:ApiKey"]; 
// This will check appsettings.json, but if an environment variable 
// named 'WeatherApi__ApiKey' exists, it will use that instead.

Notice the double underscore (__) in the environment variable name. That's a C# convention; since many operating systems don't like colons in variable names, .NET maps double underscores to the configuration hierarchy. If you're on Windows, you can set this in your system settings; on Linux, you'd add it to your .bashrc or your Docker Compose file. Your code remains agnostic to where the value comes from—it just knows it needs a key to make the API call work.




📋 Practical Task

Exercise: Securing a Third-Party API Integration for a Weather Dashboard

You have been handed a small console application that fetches weather data. Currently, the API key is hardcoded into a static class, and the application is failing to run in the production environment because the production key is different from the development key.

Your Goal: Refactor the application to remove the hardcoded secret and implement a layered configuration approach.

  • Step 1: Create an appsettings.json file. Move the BaseUrl (e.g., https://api.weatherapi.com/v1) into this file.
  • Step 2: Remove the hardcoded ApiKey string from the C# code entirely.
  • Step 3: Update the Program.cs to use ConfigurationBuilder to load both the JSON file and the Environment Variables.
  • Step 4: Modify the service to retrieve the ApiKey via IConfiguration.
  • Step 5: Test your implementation by setting a local environment variable named WeatherSettings__ApiKey on your machine and verifying that the application reads this value instead of any value found in the JSON file.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.