How to use OAuth with Swagger and NSwagStudio
Asked Answered
C

1

6

I'm trying to generate a C# client for an API that has provided a swagger.json file to me, located at this link;

https://api.ekm.net/swagger/v1/swagger.json

Using the NSwagStudo application I am able to import the configuration file and generate a file called Client.cs which implements a class called Client and it has methods on it that match the API.

However when I call any of the methods I get an "Unauthorized" exception and I can not find any way to provide the OAuth key and secret to the client or anyone doing similar with other authentication methods.

Inspecting the swagger configuration files does show that OAuth is indicated as the authentication method as follows;

"securityDefinitions": {
    "OAuth": {
        "flow": "accessCode",
        "authorizationUrl": "https://api.ekm.net/connect/authorize",
        "tokenUrl": "https://api.ekm.net/connect/token",
        "scopes": {
            "tempest.customers.read": "Read a shop's customers.",
            "tempest.customers.write": "Modify a shop's customers.",
            "tempest.orders.read": "Read a shops orders.",
            "tempest.orders.write": "Modify a shop's orders.",
            "tempest.products.read": "Read a shop's products.",
            "tempest.products.write": "Modify a shop's products.",
            "tempest.categories.read": "Read a shop's categories.",
            "tempest.categories.write": "Modify a shop's categories.",
            "tempest.settings.orderstatuses.read": "Read a shop's order statuses.",
            "tempest.settings.domains.read": "Read a shop's domains."
        },
        "type": "oauth2",
        "description": "In order to ensure the safety of our users data, we require all partner applications to register via the [Partner Dashboard](https://partners.ekm.net/). Once registered, partners are provided with an application key, which can be used during an OAuth2 handshake to create a token. This token can then used to make requests on behalf of a merchant."
    }
},

My test code is as follows;

static void Main(string[] args)
{
    var swagClient = new Client();

    var ords = swagClient.ApiV1OrdersGetAsync(1, 100).Result;  // This call throws SwaggerException: Unauthorized
}

The Client class does not have any obvious methods or properties to set the security values or any constructor parameters.

Does anyone have an example of how to achieve this?

Catgut answered 29/8, 2018 at 19:41 Comment(0)
T
7

I agree. It's kind of strange that it doesn't just accept some kind of "insert JWT here".

Anyway, this is how I've fixed it:

Inject HttpClient

Tick on the box named "Inject HttpClient via constructor" in NSwagStudio

CustomMessageHandler

Introduce a custom HttpMessageHandler:

internal class AuthTokenHttpMessageHandler: HttpClientHandler
{
    private readonly Action<HttpRequestMessage, CancellationToken> _processRequest;

    public AuthTokenHttpMessageHandler(Action<HttpRequestMessage, CancellationToken> processRequest)
    {
        _processRequest = processRequest;
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        _processRequest(request, cancellationToken);
        return base.SendAsync(request, cancellationToken);
    }
}

This handler accepts a delegate in which you can provide your JWT.

Integrating with your client

using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

public class MyService : IDisposable
{
    private readonly AuthTokenHttpMessageHandler _messageHandler;
    private readonly HttpClient _httpClient;
    private readonly MyNSwagClient _client;

    public MyService()
    {
        _messageHandler = new AuthTokenHttpMessageHandler((req, _) =>
        {
            req.Headers.Authorization = new AuthenticationHeaderValue("bearer", "your token goes here");
        });
        _httpClient = new HttpClient(_messageHandler);

        _client = new MyNSwagClient(_httpClient);
    }

    public async Task<SomeModel> GetStuffAsync(string paramenter1)
    {
        return await _client.StuffGetAsync(parameter1);
    }

    public void Dispose()
    {
        _httpClient?.Dispose();
        _messageHandler?.Dispose();
    }
}

I hope this helps you

Tutu answered 12/11, 2018 at 9:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.