Dex¶
Not available until the next release main
Introduction¶
The Testcontainers module for Dex, a CNCF-sandbox OIDC provider. The module lets Go tests spin up a real Dex instance and exercise OAuth2/OIDC flows end-to-end instead of mocking the token endpoint.
Adding this module to your project dependencies¶
Please run the following command to add the Dex module to your Go dependencies:
go get github.com/testcontainers/testcontainers-go/modules/dex
Usage example¶
ctx := context.Background()
app, err := dex.NewClient("my-app",
dex.WithClientSecret("secret"),
dex.WithClientRedirectURIs("http://localhost:8080/callback"),
dex.WithClientGrantTypes("authorization_code", "refresh_token"),
dex.WithClientName("My App"),
)
if err != nil {
log.Fatalf("new client: %v", err)
}
user, err := dex.NewUser("[email protected]", "u", "p")
if err != nil {
log.Fatalf("new user: %v", err)
}
c, err := dex.Run(ctx, "dexidp/dex:v2.45.1",
dex.WithClient(app),
dex.WithUser(user),
)
if err != nil {
log.Fatalf("run: %v", err)
}
defer func() { _ = testcontainers.TerminateContainer(c) }()
Module Reference¶
Run function¶
- Not available until the next release main
The Dex module exposes one entrypoint function to create the Dex container, and this function receives three parameters:
func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error)
context.Context, the Go context.string, the Docker image to use.testcontainers.ContainerCustomizer, a variadic argument for passing options.
Image¶
Use the second argument in the Run function to set a valid Docker image.
In example: Run(context.Background(), "dexidp/dex:v2.45.1").
Warning
The client_credentials grant requires Dex ≥ v2.46.0 or the
dexidp/dex:master image. On v2.45.x and earlier the token endpoint
returns unsupported_grant_type even with WithEnableClientCredentials()
set. The module does not validate the image tag — pin a compatible image
when using that grant.
Container Options¶
When starting the Dex container, you can pass options in a variadic way to configure it.
Clients¶
- Not available until the next release main
Client is an opaque value type. Construct it with NewClient(id, opts...)
so invalid values surface at call-site. NewClient returns
(Client, error); client options accept variadic URIs and grant types.
app, err := dex.NewClient("my-app",
dex.WithClientSecret("secret"),
dex.WithClientRedirectURIs("http://localhost:8080/callback"),
dex.WithClientGrantTypes("authorization_code", "refresh_token"),
dex.WithClientName("My App"),
)
// ...
c, err := dex.Run(ctx, "dexidp/dex:v2.45.1", dex.WithClient(app))
Additional client options: WithClientPublic() marks the client as public
(PKCE, no secret).
Clients added at runtime via AddClient inherit Dex's defaults
(authorization_code + refresh_token) because Dex's gRPC api.Client
proto has no grant_types field. Clients needing other grants must be
declared pre-start via WithClient.
Users¶
- Not available until the next release main
User is an opaque value type. NewUser(email, username, password, opts...)
returns (User, error). Use WithUserID(id) to pin the stable sub claim;
otherwise a UUIDv4 is generated at YAML render time.
user, err := dex.NewUser("[email protected]", "user", "password",
dex.WithUserID("stable-sub-123"),
)
// ...
c, err := dex.Run(ctx, "dexidp/dex:v2.45.1", dex.WithUser(user))
Adding WithUser keeps Dex's built-in password DB connector enabled. Use
WithDisablePasswordDB() to turn it off when the configuration only uses
other connectors.
Connectors¶
- Not available until the next release main
WithConnector(type, id, name) enables a Dex connector. Supported types:
ConnectorPassword— Dex's built-in static password DB. Enabled by default; no-op when passed explicitly.ConnectorMock— Dex'smockCallbacktest connector. Returns a fixed user ([email protected]) and bypasses the login form.
Blank id or name values are rejected at Run time.
Issuer¶
- Not available until the next release main
By default the issuer is derived from the host and mapped HTTP port:
http://<host>:<mappedPort>/dex. WithIssuer(url) overrides the default.
Use it when the issuer must be reachable from other containers (shared
Docker network with a network alias); the caller owns reachability.
Storage¶
- Not available until the next release main
WithStorage(Storage) selects Dex's storage backend. Available constants:
StorageSQLite— on-disk SQLite database (default). Ephemeral; destroyed with the container.StorageMemory— in-process. Fastest; not shared across replicas.
Logging¶
- Not available until the next release main
WithLogger(*slog.Logger) routes Dex container logs through a slog.Logger.
Unset by default — container logs are discarded. Stderr lines are promoted
to at least slog.LevelWarn because Dex writes runtime errors there.
WithLogLevel(slog.Level) sets Dex's own logger.level YAML key. Values
between slog's fixed levels round down. Default: slog.LevelInfo.
Client credentials grant¶
- Not available until the next release main
WithEnableClientCredentials() sets the env var
DEX_CLIENT_CREDENTIAL_GRANT_ENABLED_BY_DEFAULT=true, which Dex ≥ v2.46.0
reads to enable the OAuth2 client_credentials grant. Pair with a
compatible image (see the Image warning above).
Approval screen¶
- Not available until the next release main
WithSkipApprovalScreen(bool) toggles Dex's oauth2.skipApprovalScreen.
Default: true (tests rarely want a human-in-the-loop prompt).
The following options are exposed by the testcontainers package.
Basic Options¶
WithExposedPortsSince v0.37.0WithEnvSince v0.29.0WithWaitStrategySince v0.20.0WithAdditionalWaitStrategySince v0.38.0WithWaitStrategyAndDeadlineSince v0.20.0WithAdditionalWaitStrategyAndDeadlineSince v0.38.0WithEntrypointSince v0.37.0WithEntrypointArgsSince v0.37.0WithCmdSince v0.37.0WithCmdArgsSince v0.37.0WithLabelsSince v0.37.0
Lifecycle Options¶
WithLifecycleHooksSince v0.38.0WithAdditionalLifecycleHooksSince v0.38.0WithStartupCommandSince v0.25.0WithAfterReadyCommandSince v0.28.0
Files & Mounts Options¶
WithFilesSince v0.37.0WithMountsSince v0.37.0WithTmpfsSince v0.37.0WithImageMountSince v0.37.0
Build Options¶
WithDockerfileSince v0.37.0
Logging Options¶
WithLogConsumersSince v0.28.0WithLogConsumerConfigSince v0.38.0WithLoggerSince v0.29.0
Image Options¶
WithAlwaysPullSince v0.38.0WithImageSubstitutorsSince v0.26.0WithImagePlatformSince v0.38.0
Networking Options¶
WithNetworkSince v0.27.0WithNetworkByNameSince v0.38.0WithBridgeNetworkSince v0.38.0WithNewNetworkSince v0.27.0
Advanced Options¶
WithHostPortAccessSince v0.31.0WithConfigModifierSince v0.20.0WithHostConfigModifierSince v0.20.0WithEndpointSettingsModifierSince v0.20.0CustomizeRequestSince v0.20.0WithNameSince v0.38.0WithNoStartSince v0.38.0WithProviderSince v0.39.0
Experimental Options¶
WithReuseByNameSince v0.37.0
Container Methods¶
The Dex container exposes the following methods:
IssuerURL¶
- Not available until the next release main
Returns Dex's issuer URL. Empty if Run has not started.
ConfigEndpoint¶
- Not available until the next release main
Returns the OIDC discovery document URL (/.well-known/openid-configuration).
JWKSEndpoint¶
- Not available until the next release main
Returns the JSON Web Key Set URL (/keys).
TokenEndpoint¶
- Not available until the next release main
Returns the OAuth2 token URL (/token).
AuthEndpoint¶
- Not available until the next release main
Returns the OAuth2 authorization URL (/auth).
GRPCEndpoint¶
- Not available until the next release main
Returns host:mappedPort for Dex's gRPC admin API. Takes a context.Context
and returns an error if the container is not started or the Docker API
call fails.
target, err := c.GRPCEndpoint(ctx)
AddClient¶
- Not available until the next release main
Registers a client at runtime via Dex's gRPC admin API. Returns
ErrClientExists when the ID is already registered. Not safe for
concurrent use.
RemoveClient¶
- Not available until the next release main
Deletes a client by ID. Returns a plain error containing "not found" for
unknown IDs. Not safe for concurrent use.
AddUser¶
- Not available until the next release main
Registers a user in Dex's password DB at runtime via gRPC. Returns
ErrUserExists when the email is already registered. Not safe for
concurrent use.
RemoveUser¶
- Not available until the next release main
Deletes a user by email. Returns a plain error containing "not found" for
unknown emails. Not safe for concurrent use.
ID token claims¶
Dex's password connector emits these standard claims in ID tokens:
sub— stable user ID (auto-generated UUIDv4 whenNewUseris called withoutWithUserID).email— user's email address.email_verified— alwaystruefor static password entries.name— the username.iss— the issuer URL.aud— the client ID.
Dex does NOT emit the preferred_username claim; use the name claim
instead when a human-readable identifier is needed.
Known limitations¶
- Runtime-added clients inherit Dex's default grants.
client_credentialsrequiresWithEnableClientCredentials()and Dex ≥ v2.46.0 or the:masterimage tag.- gRPC admin API is plaintext. TLS not supported day 1.
mockCallbackemits a fixed user; parameterized flows need the password connector with a pre-seeded user.- SQLite storage is container-local and ephemeral.
- Bcrypt cost ≥ 10 is enforced by Dex for both YAML and gRPC password paths.