ASP.NET Core: User Secrets, Secret Manager and External Logins, oh my!

ASP.NET Core has a concept called user secrets. What are user secrets? Well, in short they’re usually some type of value, whether is be an AppId or AppSecret for external logins, username/passwords/resource url’s for integrations, connection strings for databases (this list goes on and one) that are accessed by a key and stored in some type of configuration file.

Recently, while wiring up Humanitarian Toolbox’s AllReady Repository Facebook external login provider, I learned the hard way about how to keep user secrets “secret” and learned about tools that ASP.NET Core and Visual Studio 2015 provide to let developers store these values locally without having to write them to a config file.


Configuration Changes in ASP.NET Core

ASP.NET Core has shifted away from storing configuration-based key/value pairs in web and app config’s, and instead, moved to storing these types of values in config.json. From there, these values can be retrieved via ASP.NET Core’s IConfiguration interface, which is a newly added abstraction over how to fetch configuration values at run time.

In ASP.NET “Classic”, we had the static ConfigurationManager class which we would use to retrieve a value from the config file via a key:

ConfigurationManager.AppSettings["KeyToGetAValueFromConfigFile"]  

In ASP.NET Core, the ConfigurationManager static class is gone. If you want to access your values stored in config.json, inject IConfiguration into the class that needs to access the value. The code will look like this:

public class ClassThatNeedsToPullValueFromConfiguration  
{  
    public ClassThatNeedsToPullValueFromConfiguration(IConfiguration configuration)  
    {   
        this.configuration = configuration;  
    }

    public void MethodPullsAValueFromConfiguration()  
    {  
        var value = configuration["[key]"];  
    }  
}  

Note: It is a best practice to use strongly typed configuration classes instead of injecting IConfiguration directly. More about strong typed configuration can be found in the docs for ASP.NET Core. For illustration purposes, I’m just using IConfiguration directly.

Regardless of how or where these key/values are stored or how we get to these values at runtime, we need somewhere we can put this sensitive information, especially in the case of open source development.


The Mistake I Made

After creating a new Facebook Application using my Facebook account and copying my AppId and AppSecret, I needed to store these two pieces of information in the ASP.NET Core site. I got caught up in the fun of working with

SignInManager<T>.GetExternalLoginInfoAsync

while wiring up the external login info code and pasted that AppId and AppSecret directly into the config.json file, then did a local Git commit.

configjson

A couple local commits later I was ready to create a PR and push the newly added sign-in logic. I referenced the GiHub Issue, created a new pull request, and the PR was off and away.

While checking up on my PR to make sure it was building successfully, I noticed that even though I had removed the AppId and AppSecret from config.json before my final local Git commit, my AppId and AppSecret were still out there as part of my Git history in the PR.

OOPS.

I had just inadvertently given the world access to my Facebook account to do whatever the hell they wanted to!


How I Fixed It

Realizing what I had done, I immediately deleted the Facebook Application the AppId and AppSecret were tied to. That kept anyone from using those credentials to do any mischief unbeknowingly on my behalf.

I quickly set out to do a little more research into how to manage user secrets. I discovered there were are a couple ways to “hide” these user secrets locally where you can still tie in values to your project without dumping all your secrets into config.json and inadvertently committing them to source control.

  1. using the secret manager via command line
  2. using the secret manager in Visual Studio 2015
  3. storing the values as environmental variables
  4. writing custom OWIN middleware and pulling these values from the persistence of your choice (database, etc…)

During my research, I found these two excellent resources that really saved my skin, one of which was was written by one of AllReady‘s project owners, CanadianJames.

In the end, I ended up downloading the Secret Manager:
DownloadSecretManager

and adding my Facebook AppId and AppSecret to the Secret Manager:

InstallAppIdAndAppSecret

If you don’t want to deal with the command line, you can also access your User Secrets via Visual Studio 2015 by right-clicking on a project:

RightClickToManageUsesSecretes

and editing the secrets.json file in the IDE:

SecretsJson

I stood the system up locally and successfully signed into the AllReady site using my Facebook account. Success!

Remember, keep those user secrets “secret” 😉

UserSecrets

Michael McCarthy

Read more posts by this author.