'Creating JWT for Epic backend authentication

I am attempting to connect to the Epic sandbox environment via a backend app. I have been following this guide but I think I am running into an issue with my JWT signature. Here is the code I am using to generate the token

class CreateJwt
{
    public static string? Token { get; set; }
    public static void Jwt()
    {

        try
        {
            
            // reading the content of a private key PEM file
            string privateKeyPem = File.ReadAllText("./private_epic_backend_key.pem");

            // keeping only the payload of the key 
            privateKeyPem = privateKeyPem.Replace("-----BEGIN PRIVATE KEY-----", "");
            privateKeyPem = privateKeyPem.Replace("-----END PRIVATE KEY-----", "");

            byte[] privateKeyRaw = Convert.FromBase64String(privateKeyPem);

            // creating the RSA key 
            RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
            provider.ImportPkcs8PrivateKey(new ReadOnlySpan<byte>(privateKeyRaw), out _);
            RsaSecurityKey rsaSecurityKey = new RsaSecurityKey(provider);

            // Generating the token 
            var now = DateTime.UtcNow;

            var claims = new[] {
                new Claim(JwtRegisteredClaimNames.Iss, "1a467f07-8a84-4e25-a493-4ba9d5ef9054"),
                new Claim(JwtRegisteredClaimNames.Sub, "1a467f07-8a84-4e25-a493-4ba9d5ef9054")
            };

            var handler = new JwtSecurityTokenHandler();

            var token = new JwtSecurityToken
            (
                "1a467f07-8a84-4e25-a493-4ba9d5ef9054",
                "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token",
                claims,
                now.AddMilliseconds(-30),
                now.AddMinutes(4),
                new SigningCredentials(rsaSecurityKey, SecurityAlgorithms.RsaSha384)
            );

            // handler.WriteToken(token) returns the token ready to send
            Token = handler.WriteToken(token);
            Console.WriteLine(Token);

        }

        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            Console.WriteLine(
                 new System.Diagnostics.StackTrace().ToString()
            );
        }

    }
}

The reason I think the issue is with the signature is because when I load the token into JWT.IO I get an "invalid signature" response. Then here is the code where I am sending it.

class GetBearerToken
{
    private static readonly HttpClient client = new HttpClient();
    public static string? Bearer { get; set; }

public async static Task Authorize()
    {
        try
        {
            var values = new Dictionary<string, string>
            {
                { "grant_type", "client_credentials" },
                { "client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" },
                { "client_assertion", CreateJwt.Token }
            };

            var content = new FormUrlEncodedContent(values);

            content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");

            var requeststring = await content.ReadAsStringAsync();
            Console.WriteLine(requeststring);

            var response = await client.PostAsync("https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token", content);

            var responseString = await response.Content.ReadAsStringAsync();

            Console.WriteLine("response from post");
            Console.WriteLine(responseString);
           
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            Console.WriteLine(
                 new System.Diagnostics.StackTrace().ToString()
            );
        }
    }
}

This looks exactly like what they are expecting according to the documentation Epic provides, but I am getting a return that states

"error": "invalid_client", "error_description": null

Epic provides a troubleshooting document that goes over this particular error, but it seems to be more of a catchall error. I have gone through the troubleshooting steps twice now and I am still not getting past this error.

Any help would be greatly appreciated.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source