Custom REST endpoint : getting the current user from keycloak AUTH_SESSION_ID cookie

I am doing a custom REST endpoint which should be called from a required action template (so, not with a JWT token but with a “pure” keycloak cookie)

In the ftl template, I am trying to do :

tmp = await fetch("/auth/realms/myrealm/myproviderid/mypath", {method:'POST'})

It correctly sends the request with a cookie AUTH_SESSION_ID (and also AUTH_SESSION_ID_LEGACY with same value)

The custom endpoint is correctly triggered

In my resource, how can I access the corresponding current user ?

I’ve tried the following but they all return null :

UserSessionModel userSession = new AuthenticationSessionManager(session).getUserSessionFromAuthCookie(session.getContext().getRealm());

UserModel user = session.getContext().getAuthenticationSession().getAuthenticatedUser()

AuthResult auth = new AppAuthManager().authenticateIdentityCookie(session, session.getContext().getRealm());

Thanks for any pointer

I reply to myself in case this can help someone in the future

First, it is usually not correct to use the REST API from a required action template

The correct thing to do is to take care of multiple actions inside processAction

    @Override
    public void processAction(RequiredActionContext context) {
        String action = context.getHttpRequest().getDecodedFormParameters().getFirst("action");
        if ("action1".equals(action)) {
            //do the logic for the action1
            if (success) {
                context.success();
            } else {
                context.challenge(context.form().setError("xxx").createForm("my.ftl"));
            }
        } else if ("action2".equals(action)) {
            //do the logic for action2 (in this example, the action always request the challenge again)
            context.challenge(context.form().createForm("my.ftl"));          
        } else {
           //by default, requst the challenge again
           context.challenge(context.form().createForm("my.ftl"));
        }
    }

in the ftl file, you can then do

        <form id="kc-action1-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
                <input type="hidden" name="action" value="action1" />              
                <input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}"                       
                       name="save" id="kc-submit" type="submit" value="${msg("action1")}"/>        
        </form>
        <form id="kc-action2-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
                <input type="hidden" name="action" value="action2" />              
                <input class=""                       
                       name="save" id="kc-submit" type="submit" value="${msg("action2")}"/>
            </div>            
        </form>

This will correctly call the corresponding if block of the processAction method

Now, if you REALLY want to call a custom REST API from inside keycloak page (without a JWT), here is what you can do

    @POST
    @NoCache
    @Path("")
    @Produces(MediaType.APPLICATION_JSON)
    public Response xxx() {
        //
        //!\ this method can be called ONLY from a keycloak page (NOT with a JWT token)
        //

        //get the realm, client and tabId from the context (/!\ for client, can not use directly context.getClient(), it is strangely always null...)
        RealmModel realm = session.getContext().getRealm();
        String clientId = session.getContext().getUri().getQueryParameters().getFirst("client_id");        
        ClientModel client = clientId != null ? session.clients().getClientByClientId(realm, clientId) : null;
        String tabId = session.getContext().getUri().getQueryParameters().getFirst("tab_id");
        if (realm == null || clientId == null || client == null || tabId == null) {
            System.out.println("bad request realm = " + realm + ", clientId = " + clientId + ", client = " + client + ", tabId = " + tabId);
            return Response.status(400).build();
        }        
        
        //find the corresponding authentication session
        AuthenticationSessionModel authSession = new AuthenticationSessionManager(session).getCurrentAuthenticationSession(realm, client, tabId);
        if (authSession == null || authSession.getAuthenticatedUser() == null) {
            System.out.println("no auth");
            return Response.status(401).build();
        }

        UserModel user = authSession.getAuthenticatedUser();
        //the rest of your code
2 Likes