private async static Task SignInAsync() { // create a redirect URI using an available port on the loopback address. string redirectUri = string.Format("http://127.0.0.1:7890/"); // create an HttpListener to listen for requests on that redirect URI. var settings = new WebListenerSettings(); settings.UrlPrefixes.Add(redirectUri); var http = new WebListener(settings); http.Start(); Console.WriteLine("Listening.."); var options = new OidcClientOptions { Authority = _authority, ClientId = "native.hybrid", RedirectUri = redirectUri, Scope = "openid profile offline_access read api", ClientSecret = "secret", FilterClaims = true, LoadProfile = true, Flow = OidcClientOptions.AuthenticationFlow.Hybrid }; var serilog = new LoggerConfiguration() .MinimumLevel.Verbose() .Enrich.FromLogContext() .WriteTo.LiterateConsole(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message}{NewLine}{Exception}{NewLine}") .CreateLogger(); options.LoggerFactory.AddSerilog(serilog); var client = new OidcClient(options); var state = await client.PrepareLoginAsync(); OpenBrowser(state.StartUrl); var context = await http.AcceptAsync(); var formData = GetRequestPostData(context.Request); if (formData == null) { Console.WriteLine("Invalid response"); return; } await SendResponseAsync(context.Response); var result = await client.ProcessResponseAsync(formData, state); options.Policy.ForceIntrospectionForAccessToken = true; //-- Test POP generation var testPop = client.CreatePopToken(new IdentityModel.OidcClient.Pop.EncodingParameters(options, result.AccessToken) { Method = "GET" }.ToJwtPayload(), result.PopTokenKey).ToSignedB64String(); Console.WriteLine($"Generated PoP Token: {testPop}"); //--Test validation... var testValidate = await client.ValidatePopToken(testPop, false, "read", "secret"); Console.WriteLine($"PoP Token Valid: {!testValidate.IsError}"); //--Test refresh var refreshResult = await client.RefreshTokenAsync(result.RefreshToken); var refreshValidate = client.CreatePopToken(new IdentityModel.OidcClient.Pop.EncodingParameters(options, refreshResult.AccessToken) { Method = "GET" }.ToJwtPayload(), refreshResult.PopTokenKey).ToSignedB64String(); var refreshValid = await client.ValidatePopToken(refreshValidate, false, "read", "secret"); var oldValidate = client.CreatePopToken(new IdentityModel.OidcClient.Pop.EncodingParameters(options, result.AccessToken) { Method = "GET" }.ToJwtPayload(), result.PopTokenKey).ToSignedB64String(); var oldValid = await client.ValidatePopToken(oldValidate, false, "read", "secret"); Console.WriteLine($"Generated PoP Token after refresh: {testPop}"); Console.WriteLine($"PoP Token (using refreshed access token) Valid: {!refreshValid.IsError}"); Console.WriteLine($"PoP Token (using old access token) Valid: {!oldValid.IsError}"); //Depending on how implemented - this should not work for an old token after the refresh token has been used. //--Revoke the tokens. var revokeClient = new TokenRevocationClient($"{options.Authority}/connect/revocation", options.ClientId, options.ClientSecret); var revokeResult = await revokeClient.RevokeRefreshTokenAsync(refreshResult.RefreshToken); Console.WriteLine($"Token revocation succeeded: {!revokeResult.IsError}"); ShowResult(result); }