You don't know how to keep your secrets.
Tags: dotnet, csharp
Published: 2023-10-15 10:16:49

I frequently faced that people keep passwords and tokens in the wrong way. Most people keep it in `appsettings` file. It's wrong. These files are only for application settings like environments, flags, and URLs. I will show you the best practices for keeping sensitive information.

Let's create a simple console application:

```
dotnet new console -n SecretsSample
```
You also need to install the required packages.

```xml
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0-rc.2.23479.6" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0-rc.2.23479.6" />
```

After that, add the base class and method for running the application.

```C#
internal static class Program
{
    static void Main(string[] args)
    {
            var environmentName = "Development";
            var host = CreateHostBuilder(args, environmentName).Build();
    }
}
```

And let's configure our host, and I'll explain what I'm doing.

```C#
internal static class Program
    {
        static void Main(string[] args)
        {
            var environmentName = "Development";
            var host = CreateHostBuilder(args, environmentName).Build();
            Console.WriteLine("Application is running...");
            host.Run();
        }

        private static IHostBuilder CreateHostBuilder(string[] args, string environmentName) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    ApplyDefaultAppConfiguration(hostingContext, config, args, environmentName);
                });

        private static void ApplyDefaultAppConfiguration(HostBuilderContext hostingContext, IConfigurationBuilder appConfigBuilder, string[]? args, string environmentName)
        {
            IHostEnvironment env = hostingContext.HostingEnvironment;
            env.EnvironmentName = environmentName;

            bool reloadOnChange = GetReloadConfigOnChangeValue(hostingContext);
            appConfigBuilder.AddJsonFile("appsettings.json", optional: true, reloadOnChange: reloadOnChange)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: reloadOnChange);
            if (env.IsDevelopment() && env.ApplicationName is { Length: > 0 })
            {
                var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
                appConfigBuilder.AddUserSecrets(appAssembly, optional: true, reloadOnChange: reloadOnChange);
            }
            appConfigBuilder.AddEnvironmentVariables();
            if (args is { Length: > 0 })
            {
                appConfigBuilder.AddCommandLine(args);
            }
        }

        static bool GetReloadConfigOnChangeValue(HostBuilderContext hostingContext) => hostingContext.Configuration.GetValue("hostBuilder:reloadConfigOnChange", defaultValue: true);
    }
```

I set the environment and created a host. Pay attention to the `ApplyDefaultAppConfiguration` method. It parses all settings, and if the environment is Development, we'll parse secrets.
Let's create a secrets file, and you need to run this command in a command line:

```
dotnet user-secrets init
```
After that, it will be created the `secrets.json` file. Which was saved in `.microsoft/usersecrets/[user secrets id]` folder. You'll get your own ID that also was added to the project:

```xml
<PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net7.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <UserSecretsId>fe9bac73-2f74-4fc5-b490-38a62750525b</UserSecretsId>
    </PropertyGroup>
```
With this ID, the application can read secrets. Let's add something to it.

```json
{
  "Hello": "World!"
}
```

To check it, let's add more code to the main method.

```C#
var config = host.Services.GetService<IConfiguration>();
            var mySettingValue = config?["Hello"];
            Console.WriteLine(string.IsNullOrEmpty(mySettingValue)
                ? "This value only for Development mode"
                : $"Hello, {mySettingValue}");
```
If you run it, you'll see the message in the console.

![console 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aad7zpvevv901kez4a5b.png)

Suppose we change the environment name to Production. We'll get a different message.

![console 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iecskhr7bi8jc1i3mq8g.png)

For the ending, I want to add the secrets.json file is not a part of the project, and you can't push it accidentally to git. However, you must pass this file if you want others to work on the project.

See you on the following week. Happy coding!
Source code: [LINK](https://github.com/SergKorol/SecretsSample)

<a href="https://www.buymeacoffee.com/b9z99kntvtQ" target="_blank"><img src="http://dartfordwaffler.co.uk/wp-content/uploads/2021/03/buy-me-a-beer.jpg" alt="Buy Me A Beer" style="height: 60px !important;width: 317px !important;" ></a>