Create AccessToken inside custom SPI

Hello
I am writing a custom SPI to implement EventListenerProvider. I want to create inside it’s implementation an AccessToken to invoke a client (SSO secured) belonging to current realm; I need the access token to invoke the client’s REST Api.
Any idea?

Thanks

There’s private APIs in Keycloak that can create a token, but I would probably rather try to use a service account and get tokens using client credentials grant. It may also be better to not use bearer tokens for this as it could easily be a bit of a chicken and an egg kinda thing.

1 Like

Is there any example / documentation on how to get the tokens of such a service account programmatically.
In my case I have an authentication plugin that needs to make a call to a client within the realm, and I would like to authenticate the service account to get the tokens and make the call.

Additionally wondering if we can cache / keep it active between plugin calls (different authentication requests)

Regards
João

Hi,
+1

I need to perform some setup tasks in another app since registration should be done in keycloak from now on.

I tried using the client credentials grant routine from org.keycloak.protocol.oidc.endpoints.TokenEndpoint in my EventListenerProvider implementation but end up duplicating a lot of code and ultimately get a java.lang.NoClassDefFoundError: org/keycloak/services/managers/AuthenticationSessionManager
The keycloak services artifact is included with scope provided in my module.
Also I do not want the service account login to be linked to the user session in any way, which I am not sure of with this method.

Best regards

Is there some documentation regarding this topic?

Is there some documentation regarding this topic?

The keycloak-quickstarts repository has an example action-token-authenticator, but it’s not specifically for access tokens.

In my case I have an authentication plugin that needs to make a call to a client within the realm, and I would like to authenticate the service account to get the tokens and make the call.

We had this same use-case on my team. We started with a service account and client credentials grant as @stianst described, but it felt clunky so we ended up using the private APIs previously referred to.

Within your authenticator, you can create an AccessToken from its representation, and then sign it using the JWSBuilder and contextual data from the KeycloakSession.

A modified snippet from our implementation:

import org.keycloak.authentication.AuthenticationFlowContext;
import org.keycloak.authentication.Authenticator;
import org.keycloak.jose.jws.JWSBuilder;
import org.keycloak.models.KeyManager;
import org.keycloak.representations.AccessToken;
import org.keycloak.services.Urls;

class ExampleToken implements Authenticator {

    @Override
    void authenticate(AuthenticationFlowContext context) {
        // build token and set required attributes
        AccessToken token = new AccessToken();
        token.audience("foo");
        token.subject("bar");
        token.issuedFor("baz");
        token.type("Bearer");
        token.setOtherClaims("foobar", "foobaz");
        token.issuer(
                Urls.realmIssuer(
                        context.getUriInfo().getBaseUri(), context.getRealm().getName()
                )
        );
        token.issuedNow();
        token.expiration((int) (token.getIat() + 120L)); // 2 minute lifespan
        
        // sign token
        KeyManager.ActiveRsaKey key = context.getSession().keys().getActiveRsaKey(context.getRealm());
        String signedToken = new JWSBuilder()
                .kid(key.getKid())
                .type("JWT")
                .jsonContent(token)
                .rsa256(key.getPrivateKey());
    }
}

Disclaimer: this was written a few years ago and relies on some deprecated methods.

3 Likes

Thank you @trotman23 for the quick reply. I will check into it.