Stream: implementers
Topic: How to authenticate with C# FHIR API to post to simplifier
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?
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;
}
}
}
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
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.
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);
}
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.
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