I'm running an application in Docker with two services: an identity service (using OpenIddict to issue tokens) and an api service (using OpenIddict validation middleware). The services are defined in my Docker Compose files as follows:
services:
api:
image: ${DOCKER_REGISTRY-}api
networks:
- documentmanagement
build:
context: .
dockerfile: Api/Dockerfile
identity:
image: ${DOCKER_REGISTRY-}identity
depends_on:
- db
build:
context: .
dockerfile: Identity/Dockerfile
networks:
- documentmanagement
networks:
documentmanagement:
name: documentmanagement
services:
api:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_HTTP_PORTS=7002
- ASPNETCORE_HTTPS_PORTS=7001
ports:
- "64589:7001"
- "64590:7002"
volumes:
- ${APPDATA}/Microsoft/UserSecrets:/home/app/.microsoft/usersecrets:ro
- ${APPDATA}/ASP.NET/Https:/home/app/.aspnet/https:ro
identity:
container_name: identity
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_HTTP_PORTS=7004
- ASPNETCORE_HTTPS_PORTS=7003
ports:
- "64587:7003"
- "64588:7004"
volumes:
- ${APPDATA}/Microsoft/UserSecrets:/home/app/.microsoft/usersecrets:ro
- ${APPDATA}/ASP.NET/Https:/home/app/.aspnet/https:ro
public static void AddOpenIddictServices(this IServiceCollection services, IConfiguration configuration, IHostEnvironment env)
{
services.AddOpenIddict()
.AddCore(options =>
{
options.UseEntityFrameworkCore()
.UseDbContext<ApplicationDbContext>();
})
.AddServer(options =>
{
options
.SetAuthorizationEndpointUris("connect/authorize")
.SetLogoutEndpointUris("connect/logout")
.SetTokenEndpointUris("connect/token")
.SetIntrospectionEndpointUris("introspect")
.SetUserinfoEndpointUris("connect/userinfo");
options.RegisterScopes(Scopes.Email, Scopes.Profile, Scopes.Roles);
options.AllowAuthorizationCodeFlow()
.AllowImplicitFlow()
.AllowClientCredentialsFlow();
options.AddDevelopmentSigningCertificate();
options.AddDevelopmentEncryptionCertificate();
options.UseAspNetCore()
.DisableTransportSecurityRequirement()
.EnableAuthorizationEndpointPassthrough()
.EnableTokenEndpointPassthrough()
.EnableUserinfoEndpointPassthrough()
.EnableLogoutEndpointPassthrough();
})
.AddValidation(options =>
{
options.UseLocalServer();
options.UseAspNetCore();
});
}
const oidcSettings: VueOidcSettings = {
authority: "http://localhost:64588",
scope: "openid profile email api1",
client_id: "nirvana-cms-spa",
client_secret: "FCAzGmhIsn3ZbGvpcIvjnstjBSIMW2KU",
redirect_uri: origin + "/oidc-callback",
post_logout_redirect_uri: origin + "/signout",
response_type: "code",
loadUserInfo: true,
userStore: new WebStorageStateStore({
prefix: "vue3-oidc",
store: window.sessionStorage,
}),
automaticSilentRenew: true,
monitorSession: true,
silent_redirect_uri: location.origin + "/silent-renew.html",
onSigninRedirectCallback(user) {
location.href = unref(state).redirect_uri || "/";
},
onBeforeSigninRedirectCallback() {
setRedirectUri(location.pathname + location.search);
},
};
builder.Services.AddOpenIddict()
.AddValidation(options =>
{
options.SetIssuer("http://identity:7004/");
options.AddAudiences("resource_server_1");
options.UseIntrospection()
.SetClientId("resource_server_1")
.SetClientSecret("846B62D0-DEF9-4215-A99D-86E6B8DAB342");
options.UseSystemNetHttp();
options.UseAspNetCore();
});
The Issue When I call protected API endpoints with a token issued by the identity service, I receive the following error in the API logs:
"error": "invalid_token",
"error_description": "The token was rejected by the remote authentication server.",
The logs indicate that the introspection endpoint is called, and the returned token introspection response is:
{ "active": false }
The log details show different URLs being used:
It appears there is a mismatch between the issuer URL embedded in the token and the issuer expected by the API validation.
There is a mismatch between the issuer URL embedded in the token and the issuer expected by the API validation.
How should I configure the identity service's issuer so that both internal (Docker service names) and external (mapped ports) communications work correctly?
What is the recommended configuration for setting up OpenIddict in a Docker environment to avoid this token introspection error?
I'm running an application in Docker with two services: an identity service (using OpenIddict to issue tokens) and an api service (using OpenIddict validation middleware). The services are defined in my Docker Compose files as follows:
services:
api:
image: ${DOCKER_REGISTRY-}api
networks:
- documentmanagement
build:
context: .
dockerfile: Api/Dockerfile
identity:
image: ${DOCKER_REGISTRY-}identity
depends_on:
- db
build:
context: .
dockerfile: Identity/Dockerfile
networks:
- documentmanagement
networks:
documentmanagement:
name: documentmanagement
services:
api:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_HTTP_PORTS=7002
- ASPNETCORE_HTTPS_PORTS=7001
ports:
- "64589:7001"
- "64590:7002"
volumes:
- ${APPDATA}/Microsoft/UserSecrets:/home/app/.microsoft/usersecrets:ro
- ${APPDATA}/ASP.NET/Https:/home/app/.aspnet/https:ro
identity:
container_name: identity
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_HTTP_PORTS=7004
- ASPNETCORE_HTTPS_PORTS=7003
ports:
- "64587:7003"
- "64588:7004"
volumes:
- ${APPDATA}/Microsoft/UserSecrets:/home/app/.microsoft/usersecrets:ro
- ${APPDATA}/ASP.NET/Https:/home/app/.aspnet/https:ro
public static void AddOpenIddictServices(this IServiceCollection services, IConfiguration configuration, IHostEnvironment env)
{
services.AddOpenIddict()
.AddCore(options =>
{
options.UseEntityFrameworkCore()
.UseDbContext<ApplicationDbContext>();
})
.AddServer(options =>
{
options
.SetAuthorizationEndpointUris("connect/authorize")
.SetLogoutEndpointUris("connect/logout")
.SetTokenEndpointUris("connect/token")
.SetIntrospectionEndpointUris("introspect")
.SetUserinfoEndpointUris("connect/userinfo");
options.RegisterScopes(Scopes.Email, Scopes.Profile, Scopes.Roles);
options.AllowAuthorizationCodeFlow()
.AllowImplicitFlow()
.AllowClientCredentialsFlow();
options.AddDevelopmentSigningCertificate();
options.AddDevelopmentEncryptionCertificate();
options.UseAspNetCore()
.DisableTransportSecurityRequirement()
.EnableAuthorizationEndpointPassthrough()
.EnableTokenEndpointPassthrough()
.EnableUserinfoEndpointPassthrough()
.EnableLogoutEndpointPassthrough();
})
.AddValidation(options =>
{
options.UseLocalServer();
options.UseAspNetCore();
});
}
const oidcSettings: VueOidcSettings = {
authority: "http://localhost:64588",
scope: "openid profile email api1",
client_id: "nirvana-cms-spa",
client_secret: "FCAzGmhIsn3ZbGvpcIvjnstjBSIMW2KU",
redirect_uri: origin + "/oidc-callback",
post_logout_redirect_uri: origin + "/signout",
response_type: "code",
loadUserInfo: true,
userStore: new WebStorageStateStore({
prefix: "vue3-oidc",
store: window.sessionStorage,
}),
automaticSilentRenew: true,
monitorSession: true,
silent_redirect_uri: location.origin + "/silent-renew.html",
onSigninRedirectCallback(user) {
location.href = unref(state).redirect_uri || "/";
},
onBeforeSigninRedirectCallback() {
setRedirectUri(location.pathname + location.search);
},
};
builder.Services.AddOpenIddict()
.AddValidation(options =>
{
options.SetIssuer("http://identity:7004/");
options.AddAudiences("resource_server_1");
options.UseIntrospection()
.SetClientId("resource_server_1")
.SetClientSecret("846B62D0-DEF9-4215-A99D-86E6B8DAB342");
options.UseSystemNetHttp();
options.UseAspNetCore();
});
The Issue When I call protected API endpoints with a token issued by the identity service, I receive the following error in the API logs:
"error": "invalid_token",
"error_description": "The token was rejected by the remote authentication server.",
The logs indicate that the introspection endpoint is called, and the returned token introspection response is:
{ "active": false }
The log details show different URLs being used:
It appears there is a mismatch between the issuer URL embedded in the token and the issuer expected by the API validation.
There is a mismatch between the issuer URL embedded in the token and the issuer expected by the API validation.
How should I configure the identity service's issuer so that both internal (Docker service names) and external (mapped ports) communications work correctly?
What is the recommended configuration for setting up OpenIddict in a Docker environment to avoid this token introspection error?
I am able to work this with some minor changes, I hope this doesn't cause another problem.
Since the Vue
client is running outside the Docker network, it needs to access the identity service using http://localhost:64588
.
I Changed the oidcSettings
to match the external URL: authority: "http://localhost:64588"
Ensured the API Uses the Same Issuer Modify your API validation to match the issuer:
builder.Services.AddOpenIddict()
.AddValidation(options =>
{
// Match the issuer with the one set in the Identity service
options.SetIssuer("http://identity:7004/");
options.AddAudiences("resource_server_1");
options.UseIntrospection()
.SetClientId("resource_server_1")
.SetClientSecret("846B62D0-DEF9-4215-A99D-86E6B8DAB342");
options.UseSystemNetHttp();
options.UseAspNetCore();
});
Modified the OpenIddict server configuration:
options.SetIssuer(new Uri("http://identity:7004/"));
public static void AddOpenIddictServices(this IServiceCollection services, IConfiguration configuration, IHostEnvironment env)
{
services.AddOpenIddict()
.AddCore(options =>
{
options.UseEntityFrameworkCore()
.UseDbContext<ApplicationDbContext>();
})
.AddServer(options =>
{
options.SetIssuer(new Uri("http://identity:7004/"))
.SetAuthorizationEndpointUris("connect/authorize")
.SetLogoutEndpointUris("connect/logout")
.SetTokenEndpointUris("connect/token")
.SetIntrospectionEndpointUris("introspect")
.SetUserinfoEndpointUris("connect/userinfo");
options.RegisterScopes(Scopes.Email, Scopes.Profile, Scopes.Roles);
options.AllowAuthorizationCodeFlow()
.AllowImplicitFlow()
.AllowClientCredentialsFlow();
options.AddDevelopmentSigningCertificate();
options.AddDevelopmentEncryptionCertificate();
options.UseAspNetCore()
.DisableTransportSecurityRequirement()
.EnableAuthorizationEndpointPassthrough()
.EnableTokenEndpointPassthrough()
.EnableUserinfoEndpointPassthrough()
.EnableLogoutEndpointPassthrough();
})
.AddValidation(options =>
{
options.UseLocalServer();
options.UseAspNetCore();
});
}