Skip to main content

Web API, external clients, and OAuth 2

This page covers two distinct needs:

  • exposing certain Lagoon controllers to an external application;
  • calling an external API that uses OAuth as its authentication mechanism.

Exposing controllers to an external client​

If you want to expose certain controllers to let an external application access your application's data, create an external access. By default, only your application's client can access the controllers.

To create an external access, you must specify:

  • a unique identifier;
  • a password;
  • the associated roles.
Warning

The client will have access to all controllers secured by the specified roles.

Adding an external client​

Server\Main.cs
protected override void OnConfigureAuthentification(AuthenticationOptions options)
{
// Ajoute un accès externe aux API sans authentification en tant qu'utilisateur.
options.AddClientWithCredential(
"SampleApiConsumption",
"mySecret",
new string[] { Roles.Admin.ToString() });

// Ajoute un accès externe aux API qui exigent une authentification utilisateur.
options.AddClientWithCredentialAndCode(
"ConnectCommand",
"mySecret",
"http://localhost:5002");
}

Give the client that needs to access the API the ClientId, for example SampleApiConsumption, and the ClientSecret, for example mySecret.

With this information, the external application can access controllers with the Admin role.

Accessing controllers from an external client​

Client externe
private async Task GetDataFromApiAsync()
{
string baseAddress = "https://localhost:5001";
HttpClient client = new HttpClient();
DiscoveryDocumentResponse disco = await client.GetDiscoveryDocumentAsync(baseAddress);
if (disco.IsError)
{
throw new Exception(disco.Error);
}

// Demande un jeton avec le client et son secret.
TokenResponse tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{
Address = disco.TokenEndpoint,
ClientId = "SampleApiConsumption",
ClientSecret = "mySecret"
});

if (tokenResponse.IsError)
{
throw new Exception(tokenResponse.Error);
}

// Appelle l'API avec le Bearer token.
HttpClient apiClient = new HttpClient();
apiClient.SetBearerToken(tokenResponse.AccessToken);

HttpResponseMessage response = await apiClient.GetAsync($"{baseAddress}/api/data/GetDemoData");
if (!response.IsSuccessStatusCode)
{
Console.WriteLine(response.StatusCode);
}
else
{
string content = await response.Content.ReadAsStringAsync();
}
}

Testing with Postman​

To verify the project's URLs, authorizations, and the token endpoint, run a request against the discovery URL https://localhost:5001/.well-known/openid-configuration.

Remember to disable SSL verification in Postman's general settings when testing locally.

Calling an external API with OAuth 2​

Lagoon does not provide a dedicated server-side helper to automatically inject an OAuth 2 token into an HttpClient. If your application needs to call an external API, use the standard .NET mechanisms (AddHttpClient, IHttpClientFactory) and explicitly implement token acquisition and the addition of the Authorization header.

Application configuration​

Add an application section describing the API to call and the OAuth information.

appsettings.json
{
"ExternalApi": {
"BaseUrl": "https://api.monservice.com",
"OAuth2": {
"TokenEndpoint": "https://api-authorization/oauth2/v2.0/token",
"ClientId": "your-client-id",
"ClientSecret": "your-client-secret",
"Scopes": [ "https://api.monservice.com/.default" ]
}
}
}

Creating the server-side client​

Server\Main.cs
protected override void OnConfigureServices(IServiceCollection services)
{
Services.Registry.RegisterServices(services);

services.AddHttpClient("ExternalApi", client =>
{
client.BaseAddress = new Uri(Configuration["ExternalApi:BaseUrl"]);
});
}

Using the client in a service or controller​

Server\Services\ExternalApiService.cs
public class ExternalApiService
{
private readonly IHttpClientFactory _httpClientFactory;

public ExternalApiService(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}

public async Task<string> GetDataAsync(CancellationToken cancellationToken = default)
{
HttpClient client = _httpClientFactory.CreateClient("ExternalApi");
string accessToken = await GetAccessTokenAsync(cancellationToken);
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);

using HttpResponseMessage response = await client.GetAsync("/api/resource", cancellationToken);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync(cancellationToken);
}
}

The GetAccessTokenAsync method is specific to the application: it must call the external OAuth 2 provider with the parameters expected by that provider.