Skip to content

v6: Support OIDC authentication #438

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 28 commits into
base: v6
Choose a base branch
from
Open

v6: Support OIDC authentication #438

wants to merge 28 commits into from

Conversation

bevzzz
Copy link
Collaborator

@bevzzz bevzzz commented Aug 7, 2025

Blocked by #437

What's changed

This PR adds support for the three OIDC authentication flows supported in other clients.

Bearer Token

An existing access_token + refresh_token pair can be readily used.

Authorization.bearerToken("access_token", "refresh_token", 900);

Resource Owner Password

Authorization.resourceOwnerPassword("dyma", "xx!!xx", List.of("email"));

If no scopes are provided, Resource Owner Password request is sent with "offline_access" scope.

After exchanging the password for an access-/refresh-token pair, then client will switch to Bearer Token flow.

Client Credentials

Authorization.clientCredentials("client-id", "client-secret", List.of("email"));

If no scopes are provided and we're authenticating against a Microsoft IdP, Client Credentials request is sent with client_id + "./default" scope.

Internals

The implementation is heavily inspired by Golang's oauth2 package, both the public API and internals.

At the root of it is the TokenProvider interface (TokenSource in Go-speak), which has one simple method Token getToken(). The io.weaviate.internal.oidc.nimbus package provides implementation for each of the supported OIDC flows, such that switching to another dependency should be rather easy (if ever necessary).

ReuseTokenProvider caches the token for as long as it remains valid and then fetches a new one using some other TokenProvider it wraps around.

Similarly, ExchangeTokenProvider takes a single-use TokenProvider to obtain a token pair in exchange for a grant (e.g. Resource Owner Password) and then creates a ReuseTokenProvider to refresh the access token continuously.

AsyncTokenProvider supports fetching tokens asynchronously as CompletableFuture<Token>, so that our AsyncClient does not have blocking calls in the chain. I extended rest.AuthenticationInterceptor to handle async requests differently. Its gRPC-twin, TokenClientCredentials, only needed a minimal change to accommodate this.

All tokens are configured with a 30s expiryDelta, which forces the client to refresh a token before it actually expires. This should prevent unauthorized access errors caused by poor timing.


Closes #421

@bevzzz bevzzz self-assigned this Aug 7, 2025
@bevzzz bevzzz changed the title V6 Support OIDC authorization v6 Support OIDC authorization Aug 7, 2025
Copy link

@orca-security-eu orca-security-eu bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Orca Security Scan Summary

Status Check Issues by priority
Passed Passed Secrets high 0   medium 0   low 0   info 0 View in Orca

bevzzz added 6 commits August 14, 2025 10:12
This is a large chagne that requester modifying some internals:
- Extended Endpoint interface with requesturl overload that takes
RestTransportOptions and builds a full request URL instead of
leaving it up to DefaultRestTrasport
- Added ExternalEndpoint that allows sending REST requests to
arbitrary URIs.
- Added a thin wrapper around Nimbus OAuth2 SDK to refresh tokens.
- Made Authorization an interface that can getTokenProvider().
Since HTTP client can use a thread pool executor,
token provider is likely to be accessed concurrently.
We only allow 1 thread at a time working with the token
bevzzz added 9 commits August 14, 2025 10:33
Added isLive to both sync/async client to ping the server
A custom HttpResponseParser handles the non-compliant
error response format that some OIDC servers (e.g. Okta)
return.

Refactored ResourceOwnerPassword flow to exchange the grant
for the access_token once and then switch to RefreshToken flow.
redirect_uri is set in the old Java client but it's
nowhere to be found Python and TS clients.

Also tests show that it's not required for exchanging tokens
Deleted NimbusTokenProvider.BearerTokenFlow class, no longer used.
Added a wrapper for WeaviateClient that can tie client's lifetime
to that of the Testcontainer that created it. That way the client,
once opened, is only closed when the container it belonged to is stopped.
Refreshing the token slightly ahead of its expiry
can help prevent phony unauthorized access errors.
@bevzzz bevzzz marked this pull request as ready for review August 14, 2025 22:34
@bevzzz bevzzz changed the title v6 Support OIDC authorization v6: Support OIDC authorization Aug 14, 2025
bevzzz added 4 commits August 18, 2025 10:13
It is possible for a refresh_token to expire after a long
period of inactivity depending on the IdP.
This ensures that a new token is fetched at least once after
the access_token expires.
@bevzzz bevzzz changed the title v6: Support OIDC authorization v6: Support OIDC authentication Aug 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant