I created an authentication server using openiddict with the authorization code and was using the sample mvc.client project to validate that everything was working properly. After the user logs in to the server and get's redirected back to the client I keep getting the error: SecurityTokenException: Unable to validate the 'id_token', no suitable ISecurityTokenValidator was found for: ''.". I believe this is when it's trying to get the access token from the authorization code. Looking at the logs on the server project, it looks like it's missing id_token in the response:
The token response was successfully returned:
{
"apiVersionNumber": "1.0.0.0",
"userName": "robClient",
".issued": "Wed, 10 Apr 2019 18:29:23 GMT",
".expires": "Wed, 10 Apr 2019 22:29:23 GMT",
"householdNumber": "4918",
"token_type": "Bearer",
"access_token": "[removed for security reasons]",
"expires_in": 14400
}.
Here's the relevant parts of my startup.cs on the server
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddAuthentication(options =>
{
options.DefaultScheme = OpenIddictValidationDefaults.AuthenticationScheme;
});
services.AddOpenIddict()
.AddCore(options => {
options.SetDefaultApplicationEntity<PPClient>();
options.SetDefaultAuthorizationEntity<PPAuthorization>();
options.SetDefaultScopeEntity<PPScope>();
options.SetDefaultTokenEntity<PPToken>();
options.AddAuthorizationStore<PPAuthorizationStore>();
options.AddApplicationStore<PPClientStore>();
options.AddScopeStore<PPScopeStore>();
options.AddTokenStore<PPTokenStore>();
})
.AddServer(options =>
{
// Register the ASP.NET Core MVC services used by OpenIddict.
// Note: if you don't call this method, you won't be able to
// bind OpenIdConnectRequest or OpenIdConnectResponse parameters.
options.UseMvc();
// Enable the token endpoint.
options.EnableTokenEndpoint("/authenticate/token");
options.EnableAuthorizationEndpoint("/authenticate/authCode");
// Enable the password flow.
options.AllowPasswordFlow();
// Enable the authorization code flow.
options.AllowAuthorizationCodeFlow();
// Allows for larger requests
options.EnableRequestCaching();
// Accept anonymous clients (i.e clients that don't send a client_id).
options.AcceptAnonymousClients();
options.DisableScopeValidation();
options.RegisterScopes(OpenIddict.Abstractions.OpenIddictConstants.Scopes.Email);
// During development, you can disable the HTTPS requirement.
if (_env.IsDevelopment())
{
options.DisableHttpsRequirement();
}
})
// Register the OpenIddict validation handler.
// Note: the OpenIddict validation handler is only compatible with the
// default token format or with reference tokens and cannot be used with
// JWT tokens. For JWT tokens, use the Microsoft JWT bearer handler.
.AddValidation();
}
Here's the relevant parts of my startup.cs on the client
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.LoginPath = new PathString("/signin");
})
.AddOpenIdConnect(options =>
{
// Note: these settings must match the application details
// inserted in the database at the server level.
options.ClientId = "1";
options.ClientSecret = "901564A5-E7FE-42CB-B10D-61EF6A8F3654";
options.RequireHttpsMetadata = false;
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
// Use the authorization code flow.
options.ResponseType = OpenIdConnectResponseType.Code;
options.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;
// Note: setting the Authority allows the OIDC client middleware to automatically
// retrieve the identity provider's configuration and spare you from setting
// the different endpoints URIs or the token validation parameters explicitly.
options.Authority = "http://localhost:15456/";
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
{
ValidateIssuer = true
};
options.Scope.Clear();
});
services.AddMvc();
services.AddSingleton<HttpClient>();
}
Do you have any idea what's causing the error? Thanks.
I found that the application needed to have the profile permission OpenIddictConstants.Permissions.Scopes.Profile and I needed to remove options.Scope.Clear() or else I get the above error. Not really sure why I have DisableScopeValidation() turned on.
It no longer errors but it doesn't seem like it's working properly. Once it complete's the signin it posts to /signin-oidc which does a 302 redirect to /. Since a post wasn't done to / it never tries to find the user.
Hum, weird, none of the steps you described should have any impact on whether an identity token is returned or not. Are you just you didn't forget to grant the openid scope when calling ticket.SetScopes()?
@PinpointTownes, you are correct, I wasn't granting the openid scope. When I did that I not longer got the error above.
Once it get's back to the client, it's still not actually logged in. I'm seeing the same behavior when I run (the sample. It still says "Welcome, Anonymous"
I finally figured it out. I was able to get the sample (and my client) to work once I set the cookie name in the startup class.
.AddCookie(options =>
{
.LoginPath = new PathString("/signin");
.Cookie.Name = "mvc.client";
})
My guess is that there is a conflict because both the client and the server are running under localhost.