The most relevant spec for authentication and API access for native apps has been recently updated.
If you are “that kind of person” that enjoys looking at diffs of pre-release RFCs – you would have spotted a new way of dealing with the system browser for desktop operating systems (e.g. Windows or MacOS).
Quoting section 7.3:
“More applicable to desktop operating systems, some environments allow apps to create a local HTTP listener on a random port, and receive URI redirects that way. This is an acceptable redirect URI choice for native apps on compatible platforms.”
IOW – your application launches a local “web server”, starts the system browser with a local redirect URI and waits for the response to come back (either a code or an error). This is much easier than trying to fiddle with custom URL monikers and such on desktop operating systems.
William Denniss – one of the authors of the above spec and the corresponding reference implementations – also created a couple of samples that show the usage of that technique for Windows desktop apps.
Inspired by that I, created a sample showing how to do OpenID Connect authentication from a console application using IdentityModel.OidcClient.
In a nutshell – it works like this:
Open a local listener
// create a redirect URI using an available port on the loopback address. string redirectUri = string.Format("http://127.0.0.1:7890/"); Console.WriteLine("redirect URI: " + redirectUri); // create an HttpListener to listen for requests on that redirect URI. var http = new HttpListener(); http.Prefixes.Add(redirectUri); Console.WriteLine("Listening.."); http.Start();
Construct the start URL, open the system browser and wait for a response
var options = new OidcClientOptions( "https://demo.identityserver.io", "native.code", "secret", "openid profile api", redirectUri); options.Style = OidcClientOptions.AuthenticationStyle.AuthorizationCode; var client = new OidcClient(options); var state = await client.PrepareLoginAsync(); Console.WriteLine($"Start URL: {state.StartUrl}"); // open system browser to start authentication Process.Start(state.StartUrl); // wait for the authorization response. var context = await http.GetContextAsync();
Process the response and access the claims and tokens
var result = await client.ValidateResponseAsync(context.Request.Url.AbsoluteUri, state); if (result.Success) { Console.WriteLine("\n\nClaims:"); foreach (var claim in result.Claims) { Console.WriteLine("{0}: {1}", claim.Type, claim.Value); } Console.WriteLine(); Console.WriteLine("Access token:\n{0}", result.AccessToken); if (!string.IsNullOrWhiteSpace(result.RefreshToken)) { Console.WriteLine("Refresh token:\n{0}", result.RefreshToken); } } else { Console.WriteLine("\n\nError:\n{0}", result.Error); } http.Stop();
Sample can be found here – have fun ;)
Filed under: IdentityModel, OAuth, OpenID Connect, WebAPI