Securing client credentials and other sensitive API authentication information that you receive from Enigma Vault or any other service provider is crucial in ensuring that no unauthorized access occurs. There's a number of right and wrong ways to secure credentials. First, let's go over some of the key definitions:
Client ID: The client ID is your public identifier issued by the authorization service, and as such is not critically sensitive. As the client ID alone can not be used to access anything without also having other sensitive values, it can be referenced and shared with trusted external partners.
Client Secret: The client secret is a secret known only to your application and the authorization service...and it should stay that way. Think of the client secret as the master password. In conjunction with the client ID, it is what authenticates your app.
Access Token: Your application receives an access token after successfully authenticating with the authorization service. The access token informs the API that the bearer of the token has been authorized to access the API and perform specific actions specified by the scope that was granted during authorization. The access token is the equivalent to a session ID and must be treated as a temporary secret.
Refresh Token: A refresh token is issued along side an access token for the purposes of acquiring a new access token later on. Access tokens generally have a short lifespan. In order to obtain a new access token, the refresh token is used with the client ID and secret. The refresh token is mainly used for user OAuth2 flows and client/app flows.
API Key: Some APIs have not adopted OAuth2 and still use an arbitrary hash or guid as its auth mechanism. In this scenario, the API key should be treated just like the client secret. In other scenarios, the API key is used in conjunction with OAuth2 for purposes other than security. In Enigma Vault's case, we use both OAuth2 and an API key. We use OAuth2/OIDC as our auth security mechanism and use API keys for billing purposes.
Here are the two general rules:
- Treat the client secret, issued tokens, and API key as passwords
- Only store what you need
Before we get to some solutions to help you store/manage these credentials, let's go over what not to do:
Don't hardcode your credentials or other secrets in your code
Your code will get shared and then shared and then shared again. One day you'll get notified that all of your credentials have been exposed on GitHub. You'll want to blame your collaborators and partner developers but you can really only blame yourself.
Don't store your credentials in a code repository
Similar as above but with a slightly different twist. Instead of hardcoding the credentials in code, you've decided to use environment variables. Good job! But...you're storing these values in a file...in the same repo as the code. Same scenario plays out as above with an inevitable sad ending.
Don't store the client secret in plain text
You're not storing passwords in the clear so why would you store the uber password, the client secret, in the clear? You must encrypt it at rest so that someone else can't fetch it and use it. But how do you do this? Read on.
Does your app reside in the cloud? There's a secrets/credential management service for you.
Using roles instead of compounding the credential problem with additional passwords, your app can leverage various cloud based services depending on your cloud provider. They handle all of the encryption/key management and with role based security, your compute environments are granted access sans passwords. Here are secrets/credential management services from the big three. Use them.
On prem/anti-cloud? You have some options.
You have options but the implementation/security complexity is on you. Good luck.
Windows: Check out Protected Configuration, dotnet user-secrets, and the ASP.NET IIS registration tool.
Linux: Kernel key retention service
And what about storing credentials in a database?
You can store client credentials within a database, but this option can have several pitfalls. For starters, you will still need to encrypt the credentials prior to placing them within the database. So you have to manage credentials/certificates/keys...to access the credentials. You also have to worry about backups, database restore proliferation (hey lets take a backup of that environment and now it becomes a new environment), etc. And then having the keys to the kingdom residing in a database elevates the risk of any SQL injection vulnerability.