OpenID Connect Client with .NET

OpenID Connect Client with .NET

Code Examples / website-integration

Overview

This tutorial provides a basic demo application created using the .NET Framework, which shows how to implement an OpenID Connect flow to obtain access and ID tokens from an OpenID Provider.

Configure the Curity Identity Server

In the Admin UI, create an OAuth Client with the following properties. Also ensure that at least one working authenticator is used, so that you are able to perform a user login once the sample is running.

  • Client ID: client-dotnet
  • Capabilites: Code Flow
  • Authentication Method: Secret
  • Client Secret: Password1
  • Redirect URI: http://localhost:5443/callback
  • Post Logout Redirect URI: http://localhost:5443
  • scope: openid read

Configure the Code Sample

The code sample uses .Net Framework 4.7 so ensure that this is installed and then use Visual Studio to open the code sample’s .sln file. The configuration settings for the secured website can then be viewed:

<appSettings>
    <add key="client_id" value="client-dotnet"/>
    <add key="client_secret" value="Password1"/>
    <add key="redirect_uri" value="http://localhost:5443/callback"/>
    <add key="scope" value="openid read"/>
    <add key="authorization_endpoint" value=""/>
    <add key="token_endpoint" value=""/>
    <add key="logout_endpoint" value=""/>
    <add key="revocation_endpoint" value=""/>
    <add key="jwks_uri" value=""/>
    <add key="issuer" value="https://login.curitydemo.com/oauth/v2/oauth-anonymous"/>
    <add key="api_endpoint" value="https://localhost:3000"/>
    <add key="base_url" value="http://localhost:5443"/>
</appSettings>

The sample uses the following base URLs by default:

ComponentBase URL
Web Applicationhttp://localhost:5443
Curity Identity Serverhttps://localhost:8443
APIhttp://localhost:3000

Under Web Properties we can see that the sample is configured to be hosted via IIS Express and to listen on port 5443:

Web Properties

Application Startup

When the code sample starts, it uses the discovery endpoint of the Curity Identity Server to load metadata describing all of the standard endpoints:

if (!String.IsNullOrEmpty(issuer))
{
    var discoveryClient = new HttpClient();

    var response = discoveryClient.GetAsync(issuer + "/.well-known/openid-configuration").Result;
    if (response.IsSuccessStatusCode)
    {
        string responseString = response.Content.ReadAsStringAsync().Result;
        JObject responseJson = JObject.Parse(responseString);

        authorization_endpoint = responseJson["authorization_endpoint"].ToString();
        token_endpoint = responseJson["token_endpoint"].ToString();
        revocation_endpoint = responseJson["revocation_endpoint"].ToString();
        logout_endpoint = responseJson["end_session_endpoint"].ToString();
        jwks_uri = responseJson["jwks_uri"].ToString();

    }
}

Test Logins

The code sample can then be run from Visual Studio, and the browser then presents its initial screen, to enable the user to sign in:

Web Login

The code implements OpenID Connect standard authentication redirect functionality by first forming a request URL with the standard parameters and redirecting the browser:

public String GetAuthnReqUrl()
{
    return authorization_endpoint + "?client_id="
        + client_id + "&response_type=code"
        + "&scope=" + scope + "&redirect_uri=" + redirect_uri;
}

Upon return, the .Net app receives an authorization code and swaps it for tokens using an authorization code grant message:

public String GetToken(String code)
{
    var values = new Dictionary<string, string>
    {
        { "grant_type", "authorization_code" },
        { "client_id", client_id},
        { "client_secret", client_secret },
        { "code" , code },
        { "redirect_uri", redirect_uri}
    };

    HttpClient tokenClient = new HttpClient();
    var content = new FormUrlEncodedContent(values);
    var response = tokenClient.PostAsync(token_endpoint, content).Result;
}

Use Access Tokens

The web back end then receives opaque access and refresh tokens, and operations on them can be tested from within the web app:

Logged In App

The C# application could verify received tokens and return data directly, though it is more common these days for a web back end to call APIs instead. No API is provided with the sample, but the HomeController class demonstrates how to make an outgoing call, by adding a bearer token to the HTTP Authorization Header:

String access_token = Session["access_token"].ToString();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", access_token);

var response = client.GetAsync(api_endpoint).Result;
Session["api_response_status_code"] = response.StatusCode;

To work with a real API you could adapt the .Net API Code Sample. For a full end to end solution an API Gateway should also be integrated, using the Phantom Token Pattern.

Logout

Finally the sample can be used to perform a logout operation, and to revoke tokens if required. A post_logout_redirect_uri value is supplied to ensure that the user is returned to the home page when the logout operation completes.

public class LogoutController : Controller
{
    private static string client_id = App_Start.AppConfig.Instance.GetClientId();
    private static string logout_endpoint = App_Start.AppConfig.Instance.GetLogoutEndpoint();
    private static string base_url = App_Start.AppConfig.Instance.GetBaseUrl();

    public ActionResult Index()
    {
        Session.Abandon();

        string logout_request = $"{logout_endpoint}?client_id={client_id}&post_logout_redirect_uri={HttpUtility.UrlEncode(base_url)}";
        return Redirect(logout_request);
    }
}

Conclusion

We demonstrated the basics of an OpenID Connect flow in C#, resulting in a web application that uses a number of standards based endpoints. This enables features for login, logout and working with tokens, including calls to OAuth secured APIs.

Let’s Stay in Touch!

Get the latest on identity management, API Security and authentication straight to your inbox.

Keep up with our latest articles and how-tos using RSS feeds