Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fhir Epic Sandbox : Creating a JWT in C# to Obtain an Access Token for a Backend Service #198

Open
fayazshaik07 opened this issue Jan 10, 2024 · 1 comment

Comments

@fayazshaik07
Copy link

I'm trying to use the sandbox from https://fhir.epic.com/ for Backend Services.

I am following this tutorial : https://fhir.epic.com/Documentation?docId=oauth2&section=BackendOAuth2Guide

I should send a POST request to this URL: https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token

Below is my code

    static async System.Threading.Tasks.Task GetFHIRToken()
    {
        string clientId = "883a61da-4fb3-465b-8ac0-531dd0b673fe";
        string privateKeyPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads", "privatekey.pem");
        string tokenEndpoint = "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token";

        var jwt = GenerateJwt(clientId, privateKeyPath);

        using (var client = new HttpClient())
        {
            var requestData = new Dictionary<string, string>
        {
            { "grant_type", "client_credentials" },
            { "client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" },
            { "client_assertion", jwt }
        };

            var response = await client.PostAsync(tokenEndpoint, new FormUrlEncodedContent(requestData));
            if (!response.IsSuccessStatusCode)
            {
                Console.WriteLine($"Error: {response.StatusCode} - {response.ReasonPhrase}");
                var errorContent = await response.Content.ReadAsStringAsync();
                Console.WriteLine($"Error Content: {errorContent}");
            }
            else
            {
                var responseData = await response.Content.ReadAsStringAsync();
                Console.WriteLine(responseData);
            }
            var responseContent = await response.Content.ReadAsStringAsync();

            Console.WriteLine(responseContent);
        }
    }

    static string GenerateJwt(string clientId, string privateKeyPath)
    {
        var privateKey = File.ReadAllText(privateKeyPath);

        var rsa = new RSACryptoServiceProvider();
        rsa.ImportFromPem(privateKey);

        var now = DateTime.UtcNow;
        var expires = now.AddMinutes(5);

        var handler = new JwtSecurityTokenHandler();
        var token = handler.CreateToken(new SecurityTokenDescriptor
        {
            Issuer = clientId,
            Audience = "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token",
            NotBefore = now,
            Expires = expires,
            SigningCredentials = new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha384)
        });

        var tokenString = handler.WriteToken(token);
        return tokenString;
    }

public static class RSAExtensions
{
public static RSAParameters GetParametersFromPem(byte[] pemBytes)
{
    var pemString = Encoding.UTF8.GetString(pemBytes);
    var lines = pemString.Split('\n');
    var keyBytes = Convert.FromBase64String(string.Join("", lines[1..^1]));

    using (var rsa = RSA.Create())
    {
        rsa.ImportSubjectPublicKeyInfo(keyBytes, out _);
        return rsa.ExportParameters(false);
    }
}

}

Using the above code, I'm getting the below error

{
"error": "invalid_client",
"error_description": null
}

not sure what is it I'm missing.

@tub0ng
Copy link

tub0ng commented Jul 16, 2024

Hi, do you have the solution for this issue? Could you please share?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants