AskMe
AskMe

Reputation: 2583

How to get access token without using clientId and clientSecret in .Net 4.5 application?

I have to use the REST API with .Net framework 4 and 4.5. My applications are hosted both in Azure ( as app service) and on Azure VM.

I know there Azure has a concept of managed identity. However, I'm trying to implement fetching secrets from Azure Key vault using REST API. The applications are using .Net framework 4 and 4.5.

The code is as below:

    string keyVaultUrl = "https://KeyVault.vault.azure.net";
    string secretName = "Test";
   
    string tenantId = "tenantId"; 
    string clientId = "clientId";  
    string clientSecret = "clientSecret Vaule "; 

I'm getting a access token by calling a custom method as below:

 string accessToken = await GetAccessToken(tenantId, clientId, clientSecret);

The above code works fine.

For me, it's like fetching one secret from the Key vault by exposing another secret.

I have seen lots of post says using "managed identity". As I said earlier, I have to use the REST API with .Net framework 4 and 4.5. My applications are hosted both in Azure ( as app service) and on Azure VM. I believe in this case "managed identity" is not applicable - specifically when it comes to REST and .Net 4/.net 4.5 and when application does not supports required Key vault and Entra ID related namespace ( e.g. key vault "Microsoft.Azure.KeyVault" namespace.)

My question is what is the best ways to store "clientSecret" as its getting used to fetch the secrets from Key vault ? Where can I store the client "clientSecret" and use in the code?

Upvotes: 0

Views: 198

Answers (2)

Rukmini
Rukmini

Reputation: 16064

Note that: ClientID is mandatory to generate access token, if you do not want to make use of client secret then you can generate access token using Interactive flow or Username/Password flow.

For an application to make it as Public you need to set Allow public client flows as YES:

enter image description here

But according to Microsoft Username/Password flow is not recommended due to security issues.

class Program
{
    private const string TenantId = "your-tenant-id"; 
    private const string ClientId = "your-client-id"; 
    private const string Resource = "https://vault.azure.net"; 

    static async Task Main(string[] args)
    {
        string username = "[email protected]"; 
        string password = "yourpassword"; 

        try
        {
            var app = PublicClientApplicationBuilder.Create(ClientId)
                .WithTenantId(TenantId)
                .Build();

            var securePassword = new System.Security.SecureString();
            foreach (char c in password)
            {
                securePassword.AppendChar(c);
            }

            var result = await app.AcquireTokenByUsernamePassword(
                new[] { $"{Resource}/.default" },
                username,
                securePassword)
                .ExecuteAsync();

            Console.WriteLine("Access Token: " + result.AccessToken);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error: " + ex.Message);
        }
    }
}

You can also make use of InteractiveBrowserCredential flow which do not need client secret:

class Program
{
    private const string ClientId = "ClientID"; 
    private const string TenantId = "TenantID"; 
    private const string Resource = "https://vault.azure.net";

    static async Task Main(string[] args)
    {
        var credential = new InteractiveBrowserCredential(new InteractiveBrowserCredentialOptions
        {
            ClientId = ClientId,
            TenantId = TenantId
        });

        var tokenRequestContext = new TokenRequestContext(new[] { $"{Resource}/.default" });

        var token = await credential.GetTokenAsync(tokenRequestContext);

        Console.WriteLine("Access Token: " + token.Token);
    }
}

enter image description here

If the above does not resolve the issue, then you have to Store the clientSecret in environment variables. This is a simple method and keeps sensitive data out of your codebase as suggested by Provadis.

string clientSecret = Environment.GetEnvironmentVariable("YourClientSecretEnvironmentVariable");
  • OR use a separate method to fetch the clientSecret before using it to obtain the access token.
string clientSecret = await GetSecretFromKeyVault(keyVaultUrl, "YourClientSecretName");
string accessToken = await GetAccessToken(tenantId, clientId, clientSecret);

Upvotes: 1

Provadis
Provadis

Reputation: 13

As far as i know, the common method is to store secrets, such as the secret to access the key vault, in environment variables and then accessing the env-vars through your code.

Is this helpfull?

Upvotes: 1

Related Questions