FHIR Chat · How to authenticate with C# FHIR API to post to simplifier · implementers

Stream: implementers

Topic: How to authenticate with C# FHIR API to post to simplifier


view this post on Zulip Chris Munro (Sep 01 2017 at 10:25):

I'm trying to post a structure definition to a simplifier project, I have the project endpoint and tried the following but get an error 'unauthorised' using the code below

var uri = new Uri(simplifierEndpoint);
var uriWithCred = new UriBuilder(uri) { UserName = "myusername", Password = "mypassword" }.Uri;
var client = new FhirClient(uriWithCred);

FhirXmlParser parser = new FhirXmlParser();
StructureDefinition stdef = parser.Parse<StructureDefinition>(XMLstr); //XMLstr is file with profile
client.Create<StructureDefinition>(stdef);

I'm wondering if @Mirjam Baltus , @Ewout Kramer or @Michel Rutten could help?

view this post on Zulip Michel Rutten (Sep 01 2017 at 10:52):

Hi @Chris Munro, you should add the credentials to the http headers. In Forge we use a small utility class:

var _basicAuthDecorator = new BasicAuth(endpoint, credentials);
// ...
using (var client = new SimplifierWebClient(Timeout))
{
    // add basic authentication
    _basicAuthDecorator.AddAuthentication(client.Headers);

    client.Encoding = Encoding.UTF8;
    client.DownloadString(...)
}

--- BasicAuth.cs ---

using System;
using System.Net;
using System.Text;

namespace Forge.ViewModels
{
    public sealed class BasicAuth
    {
        private readonly string authenticationType;
        private readonly ICredentials credentials;
        public Uri ServerUrl { get; private set; }

        // Initialize the endpoint URL and the credentials for authentication
        public BasicAuth(Uri serverUrl, ICredentials credentials)
        {
            this.credentials = credentials;
            ServerUrl = serverUrl;
            authenticationType = "Basic ";
        }

        // Initialize the endpoint URL and the credentials for authentication
        public BasicAuth(string serverUrl, ICredentials credentials) : this(new Uri(serverUrl), credentials)
        {
        }

        // Add basic authentication to the request
        public void AddAuthentication(WebHeaderCollection headers)
        {
            if (credentials == null) return; // no credentials given, proceed without authentication
            var networkCredentials = credentials.GetCredential(ServerUrl, authenticationType);
            if (networkCredentials.UserName == null) return; // no credentials given, proceed without authentication
            var encodedCredentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(networkCredentials.UserName + ":" + networkCredentials.Password));
            headers[HttpRequestHeader.Authorization] = authenticationType + encodedCredentials;
        }
    }
}

view this post on Zulip Chris Munro (Sep 01 2017 at 14:11):

Thanks @Michel Rutten, is the URL https://stu3.simplifier.net/ELabTest2 the correct one to put in? I tried even with postman to post an XML file to this URL with the username/password in the header and I get a 404 not found error

view this post on Zulip Michel Rutten (Sep 01 2017 at 14:23):

Hi @Chris Munro, the project url appears to be correct.

I forgot to mention that you need to hook/override FhirClient.(On)BeforeRequest and add credential headers, e.g. using

basicAuthDecorator.AddAuthentication(rawRequest.Headers);

I can succesfully publish profiles to my Forge STU3 demo project on Simplifier, so there are no issues on the server.

view this post on Zulip Michel Rutten (Sep 01 2017 at 14:35):

I just realized that the logic I posted earlier is for retrieving a list of personal projects from Simplifier. This is a custom operation, not a FHIR call.

To actually publish a profile to Simplifier, Forge uses a specialized FhirClient with OnBeforeRequest hook to add http heades for credentials (using BasicAuth utility class above):

public sealed class SimplifierFhirClient : FhirClient
{
    private readonly BasicAuth basicAuthDecorator;

    public SimplifierFhirClient(Uri serverUrl, ICredentials credentials, bool verifyFhirVersion = false) : base(serverUrl, verifyFhirVersion)
    {
        basicAuthDecorator = new BasicAuth(serverUrl, credentials);
    }

    public SimplifierFhirClient(Uri serverUrl, string projectName, ICredentials credentials, bool verifyFhirVersion = false)
        : this(new Uri(serverUrl, projectName), credentials, verifyFhirVersion)
    {
    }

    protected override void BeforeRequest(HttpWebRequest rawRequest, byte[] body)
    {
        base.BeforeRequest(rawRequest, body);
        // ER 22-03-2016 add default accept [Spark: bugfix 9c64d8a3 (8/1/2016)]
        PreferredFormat = ResourceFormat.Json;
        basicAuthDecorator.AddAuthentication(rawRequest.Headers);
    }

    // DEBUGGING
#if DEBUG
    protected override void AfterResponse(HttpWebResponse webResponse, byte[] body)
    {
        base.AfterResponse(webResponse, body);

        // var s = System.Text.Encoding.UTF8.GetString(body);
        // System.IO.File.WriteAllText(@"D:\test.xml", s)
    }
#endif

}

Here's the calling logic:

            var client = new SimplifierFhirClient(url, new NetworkCredential(userName, password));

            T result;
            if (string.IsNullOrEmpty(resource.Id))
            {
                result = client.Create(resource);
            }
            else
            {
                result = client.Update(resource);
            }

view this post on Zulip Chris Munro (Sep 01 2017 at 15:04):

Fab! Thank you @Michel Rutten that's really helpful. I was getting into a bit of a mess but with the last post I've managed to get it working.

view this post on Zulip Michel Rutten (Sep 01 2017 at 15:07):

Great, happy to help out!
Sorry for the confusing first post. Friday afternoon... ;p


Last updated: Apr 12 2022 at 19:14 UTC