3.2.13. Integration with GitHub and non-OIDC OAuth2 providers


Some well-known providers such as GitHub or LinkedIn are not OpenID Connect providers, but OAuth2 providers that support the authorization code flow. For example, GitHub OAuth2 and LinkedIn OAuth2. Remember, OIDC is built on top of OAuth2.

The main difference between OIDC and OAuth2 providers is that OIDC providers return an ID Token that represents a user authentication, in addition to the standard authorization code flow access and refresh tokens returned by OAuth2 providers.

OAuth2 providers such as GitHub do not return IdToken, and the user authentication is implicit and indirectly represented by the access token. This access token represents an authenticated user authorizing the current Quarkus web-app application to access some data on behalf of the authenticated user.

For OIDC, you validate the ID token as proof of authentication validity whereas in the case of OAuth2, you validate the access token. This is done by subsequently calling an endpoint that requires the access token and that typically returns user information. This approach is similar to the OIDC UserInfo approach, with UserInfo fetched by Quarkus OIDC on your behalf.

For example, when working with GitHub, the Quarkus endpoint can acquire an access token, which allows the Quarkus endpoint to request a GitHub profile for the current user.

To support the integration with such OAuth2 servers, quarkus-oidc needs to be configured a bit differently to allow the authorization code flow responses without IdToken: quarkus.oidc.authentication.id-token-required=false.

注記

Even though you configure the extension to support the authorization code flows without IdToken, an internal IdToken is generated to standardize the way quarkus-oidc operates. You use an internal IdToken to support the authentication session and to avoid redirecting the user to the provider, such as GitHub, on every request. In this case, the IdToken age is set to the value of a standard expires_in property in the authorization code flow response. You can use a quarkus.oidc.authentication.internal-id-token-lifespan property to customize the ID token age. The default ID token age is 5 minutes, which you can extend further as described in the session management section.

This simplifies how you handle an application that supports multiple OIDC providers.

The next step is to ensure that the returned access token can be useful and is valid to the current Quarkus endpoint. The first way is to call the OAuth2 provider introspection endpoint by configuring quarkus.oidc.introspection-path, if the provider offers such an endpoint. In this case, you can use the access token as a source of roles using quarkus.oidc.roles.source=accesstoken. If no introspection endpoint is present, you can attempt instead to request UserInfo from the provider as it will at least validate the access token. To do so, specify quarkus.oidc.token.verify-access-token-with-user-info=true. You also need to set the quarkus.oidc.user-info-path property to a URL endpoint that fetches the user info (or to an endpoint protected by the access token). For GitHub, since it does not have an introspection endpoint, requesting the UserInfo is required.

注記

Requiring UserInfo involves making a remote call on every request.

Therefore, UserInfo is embedded in the internal generated IdToken and saved in the encrypted session cookie. It can be disabled with quarkus.oidc.cache-user-info-in-idtoken=false.

Alternatively, you might want to consider caching UserInfo using a default or custom UserInfo cache provider. For more information, see the Token Introspection and UserInfo cache section of the "OpenID Connect (OIDC) Bearer token authentication" guide.

Most well-known social OAuth2 providers enforce rate-limiting so there is a high chance you will prefer to have UserInfo cached.

OAuth2 servers might not support a well-known configuration endpoint. In this case, you must disable the discovery and configure the authorization, token, and introspection and UserInfo endpoint paths manually.

For well-known OIDC or OAuth2 providers, such as Apple, Facebook, GitHub, Google, Microsoft, Spotify, and X (formerly Twitter), Quarkus can help significantly simplify your application’s configuration with the quarkus.oidc.provider property. Here is how you can integrate quarkus-oidc with GitHub after you have created a GitHub OAuth application. Configure your Quarkus endpoint like this:

quarkus.oidc.provider=github
quarkus.oidc.client-id=github_app_clientid
quarkus.oidc.credentials.secret=github_app_clientsecret

# user:email scope is requested by default, use 'quarkus.oidc.authentication.scopes' to request different scopes such as `read:user`.
# See https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps for more information.

# Consider enabling UserInfo Cache
# quarkus.oidc.token-cache.max-size=1000
# quarkus.oidc.token-cache.time-to-live=5M
#
# Or having UserInfo cached inside IdToken itself
# quarkus.oidc.cache-user-info-in-idtoken=true

For more information about configuring other well-known providers, see OpenID Connect providers.

This is all that is needed for an endpoint like this one to return the currently-authenticated user’s profile with GET http://localhost:8080/github/userinfo and access it as the individual UserInfo properties:

package io.quarkus.it.keycloak;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;

import io.quarkus.oidc.UserInfo;
import io.quarkus.security.Authenticated;

@Path("/github")
@Authenticated
public class TokenResource {

    @Inject
    UserInfo userInfo;

    @GET
    @Path("/userinfo")
    @Produces("application/json")
    public String getUserInfo() {
        return userInfo.getUserInfoString();
    }
}

If you support more than one social provider with the help of OpenID Connect Multi-Tenancy, for example, Google, which is an OIDC provider that returns IdToken, and GitHub, which is an OAuth2 provider that does not return IdToken and only allows access to UserInfo, then you can have your endpoint working with only the injected SecurityIdentity for both Google and GitHub flows. A simple augmentation of SecurityIdentity will be required where a principal created with the internally-generated IdToken will be replaced with the UserInfo-based principal when the GitHub flow is active:

package io.quarkus.it.keycloak;

import java.security.Principal;

import jakarta.enterprise.context.ApplicationScoped;

import io.quarkus.oidc.UserInfo;
import io.quarkus.security.identity.AuthenticationRequestContext;
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.security.identity.SecurityIdentityAugmentor;
import io.quarkus.security.runtime.QuarkusSecurityIdentity;
import io.smallrye.mutiny.Uni;
import io.vertx.ext.web.RoutingContext;

@ApplicationScoped
public class CustomSecurityIdentityAugmentor implements SecurityIdentityAugmentor {

    @Override
    public Uni<SecurityIdentity> augment(SecurityIdentity identity, AuthenticationRequestContext context) {
        RoutingContext routingContext = identity.getAttribute(RoutingContext.class.getName());
        if (routingContext != null && routingContext.normalizedPath().endsWith("/github")) {
	        QuarkusSecurityIdentity.Builder builder = QuarkusSecurityIdentity.builder(identity);
	        UserInfo userInfo = identity.getAttribute("userinfo");
	        builder.setPrincipal(new Principal() {

	            @Override
	            public String getName() {
	                return userInfo.getString("preferred_username");
	            }

	        });
	        identity = builder.build();
        }
        return Uni.createFrom().item(identity);
    }

}

Now, the following code will work when the user signs into your application by using Google or GitHub:

package io.quarkus.it.keycloak;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;

import io.quarkus.security.Authenticated;
import io.quarkus.security.identity.SecurityIdentity;

@Path("/service")
@Authenticated
public class TokenResource {

    @Inject
    SecurityIdentity identity;

    @GET
    @Path("/google")
    @Produces("application/json")
    public String getGoogleUserName() {
        return identity.getPrincipal().getName();
    }

    @GET
    @Path("/github")
    @Produces("application/json")
    public String getGitHubUserName() {
        return identity.getPrincipal().getName();
    }
}

Possibly a simpler alternative is to inject both @IdToken JsonWebToken and UserInfo and use JsonWebToken when handling the providers that return IdToken and use UserInfo with the providers that do not return IdToken.

You must ensure that the callback path you enter in the GitHub OAuth application configuration matches the endpoint path where you want the user to be redirected after a successful GitHub authentication and application authorization. In this case, it has to be set to http://localhost:8080/github/userinfo.

Red Hat logoGithubredditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

Red Hat ドキュメントについて

Legal Notice

Theme

© 2026 Red Hat
トップに戻る