[java-oidc-common] 12/20: Copy over UserInfo lookup encoders and decoders from the RP

Codeberg noreply at shibboleth.net
Tue Feb 17 20:14:47 UTC 2026


This is an automated email from the git hooks/post-receive script.

codeberg pushed a commit to branch dev/JCOMOIDC-139
in repository java-oidc-common.

View the commit online:
https://codeberg.org/Shibboleth/java-oidc-common/commit/fc2e600ef9dcafcc7d81270e45ef5034b21df36a

commit fc2e600ef9dcafcc7d81270e45ef5034b21df36a
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Wed Nov 19 16:41:56 2025 +0000

    Copy over UserInfo lookup encoders and decoders from the RP
---
 .../claims/impl/SubFromIDTokenLookupFunction.java  |  88 +++++++++
 .../config/logic/UserInfoLookupPredicate.java      |  49 +++++
 .../UserInfoHttpRequestMethodLookupStrategy.java   |  45 +++++
 .../decoding/impl/UserInfoResponseDecoder.java     | 135 ++++++++++++++
 .../encoding/impl/UserInfoRequestEncoder.java      | 200 +++++++++++++++++++++
 5 files changed, 517 insertions(+)

diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/jwt/claims/impl/SubFromIDTokenLookupFunction.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/jwt/claims/impl/SubFromIDTokenLookupFunction.java
new file mode 100644
index 00000000..a8ddad89
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/jwt/claims/impl/SubFromIDTokenLookupFunction.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.security.jwt.claims.impl;
+
+import java.text.ParseException;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.openid.connect.sdk.OIDCTokenResponse;
+
+import net.shibboleth.oidc.profile.context.AccessTokenResponseContext;
+import net.shibboleth.shared.annotation.ParameterName;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+/**
+ * A function that pulls the subject 'sub' out of the id_token in the {@link AccessTokenResponseContext}.
+ */
+ at ThreadSafe
+public class SubFromIDTokenLookupFunction extends AbstractTokenResponseLookupStrategy
+                                    implements BiFunction<ProfileRequestContext, JWTClaimsSet, String> {
+
+    /** Class logger. */
+    @Nonnull
+    private final Logger log = LoggerFactory.getLogger(SubFromIDTokenLookupFunction.class);
+
+
+    /** Constructor. */
+    public SubFromIDTokenLookupFunction() {
+        super();
+    }
+
+    /**
+     * 
+     * Constructor.
+     *
+     * @param strategy the AccessTokenResponseContext lookup strategy to use.
+     */
+    public SubFromIDTokenLookupFunction(@Nonnull @ParameterName(name="accessTokenContextLookupStrategy") 
+                    final Function<ProfileRequestContext, AccessTokenResponseContext> strategy) {
+        super(strategy);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * The input claims set is ignored because it belongs to the JWT that is being tested. Here we lookup
+     * the 'sub' claim from the id_token in a different context.
+     */
+    @Override
+    @Nullable
+    public String apply(@Nullable final ProfileRequestContext prc, @Nullable final JWTClaimsSet claimsSet) {
+        final AccessTokenResponseContext tokenContext = getTokenResponseContextLookupStrategy().apply(prc);
+        final OIDCTokenResponse tokenResponse = tokenContext != null ?  tokenContext.getTokenResponse() : null;
+        if (tokenResponse == null || tokenResponse.getOIDCTokens().getIDToken() == null) {
+            return null;
+        }
+        try {
+            final JWTClaimsSet claims = tokenResponse.getOIDCTokens().getIDToken().getJWTClaimsSet();
+            if (claims != null && claims.getSubject() != null) {
+                return claims.getSubject();
+            }
+        } catch (final ParseException e) {
+            log.warn("Unable to parse id_token claims, can not extract subject", e);
+        }
+        return null;
+    }
+
+}
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/logic/UserInfoLookupPredicate.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/logic/UserInfoLookupPredicate.java
new file mode 100644
index 00000000..a8aa6b53
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/logic/UserInfoLookupPredicate.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.profile.config.logic;
+
+import java.util.function.Predicate;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.oidc.profile.config.OIDCAuthenticationRelyingPartyProfileConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+
+/**
+ * Checks whether the UserInfo endpoint should be accessed to retrieve claims about the
+ * authenticated end-user. Defaults to true, unless overridden in the profile configuration.
+ */
+public class UserInfoLookupPredicate implements Predicate<ProfileRequestContext> {
+
+    @Override
+    public boolean test(@Nullable final ProfileRequestContext prc) {
+        if (prc == null) {
+            return true;
+        }
+        final RelyingPartyContext rpCtx = prc.getSubcontext(RelyingPartyContext.class);
+        if (rpCtx != null && rpCtx.getProfileConfig() != null &&
+                rpCtx.getProfileConfig() instanceof OIDCAuthenticationRelyingPartyProfileConfiguration rpConfig) {
+            return rpConfig.isRetrieveUserInfoEndpointClaims(prc);
+        }
+        
+        // Perform user info lookup by default if no config found
+        return true;
+        
+        
+    }
+
+}
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/navigate/UserInfoHttpRequestMethodLookupStrategy.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/navigate/UserInfoHttpRequestMethodLookupStrategy.java
new file mode 100644
index 00000000..5eb41718
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/navigate/UserInfoHttpRequestMethodLookupStrategy.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.profile.config.navigate;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.oidc.profile.config.OIDCAuthenticationRelyingPartyProfileConfiguration;
+import net.shibboleth.oidc.profile.oauth2.config.OAuth2AuthorizationProfileConfiguration.HttpRequestMethod;
+import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.profile.context.navigate.AbstractRelyingPartyLookupFunction;
+
+/** 
+ * Locate the HTTP request method to use for the UserInfo request. Returns {@link HttpRequestMethod#GET} if not 
+ * found on the profile configuration.
+ */
+public class UserInfoHttpRequestMethodLookupStrategy extends AbstractRelyingPartyLookupFunction<HttpRequestMethod> {
+    
+    @Override
+    @Nullable public HttpRequestMethod apply(final ProfileRequestContext input) {
+        final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
+        if (rpc != null) {
+            final ProfileConfiguration pc = rpc.getProfileConfig();
+            if (pc instanceof OIDCAuthenticationRelyingPartyProfileConfiguration rpConfig){
+                   return rpConfig.getUserInfoHttpRequestMethod(input);
+            }
+        }
+        return HttpRequestMethod.GET;
+    }
+
+}
diff --git a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/decoding/impl/UserInfoResponseDecoder.java b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/decoding/impl/UserInfoResponseDecoder.java
new file mode 100644
index 00000000..773e4d84
--- /dev/null
+++ b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/decoding/impl/UserInfoResponseDecoder.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.profile.decoding.impl;
+
+import java.io.InputStream;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpStatus;
+import org.slf4j.Logger;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.nimbusds.common.contenttype.ContentType;
+import com.nimbusds.jose.util.IOUtils;
+import com.nimbusds.jwt.JWT;
+import com.nimbusds.jwt.JWTParser;
+import com.nimbusds.openid.connect.sdk.UserInfoErrorResponse;
+import com.nimbusds.openid.connect.sdk.UserInfoResponse;
+import com.nimbusds.openid.connect.sdk.UserInfoSuccessResponse;
+import com.nimbusds.openid.connect.sdk.claims.ClaimsSet;
+import com.nimbusds.openid.connect.sdk.claims.UserInfo;
+
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+
+/** 
+ * A UserInfo response decoder. Supports both plain JSON Object and JWT responses. 
+ * 
+ * <p>Importantly,the decoder *must not ever* decode a JWT response as a plain response type, otherwise the signature 
+ * check may not be performed downstream - although other validation for the plain object type should. That is, we 
+ * can not rely solely on the content-type header in-case of content-type header injection attacks — the logic 
+ * that builds either the JWT or plain response should fail, or at least present an invalid UserInfo response token.
+ * Any decoding error is logged and {@code null} is returned.</p>
+ */
+public class UserInfoResponseDecoder extends AbstractJSONResponseDecoderFunction<UserInfoResponse> {
+    
+    /** The UserInfo response header that carries error information.*/
+    @Nonnull public static final String USERINFO_ERROR_RESPONSE_HEADER = "WWW-Authenticate";
+    
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(UserInfoResponseDecoder.class);    
+    
+ // Checkstyle: CyclomaticComplexity|ReturnCount|MethodLength OFF
+    @Override
+    public UserInfoResponse handleResponse(@Nullable final ClassicHttpResponse httpResponse) {
+        
+        if (httpResponse == null) {
+            log.error("HttpResponse was null, can not process response");
+            return null;
+        }
+        
+        try {
+            final int httpStatusCode = httpResponse.getCode();
+            
+            if (httpStatusCode != HttpStatus.SC_OK) {  
+                final Header errorHeader = httpResponse.getHeader(USERINFO_ERROR_RESPONSE_HEADER);
+                
+                if (errorHeader != null) {
+                    return UserInfoErrorResponse.parse(errorHeader.getValue());
+                } else {
+                    log.warn("HTTP status code implies error response, but no error given");
+                    return null;
+                }
+                
+            } else {
+                // Response indicates success
+                final HttpEntity entity = httpResponse.getEntity();
+                if (entity == null) {
+                    log.warn("HTTP response did not contain a response entity, nothing to decode");
+                    return null;
+                }
+                final String contentTypeString = entity.getContentType();
+                if (contentTypeString == null) {
+                    log.warn("HTTP response did not contain a content-type, must contain a content-type");
+                    return null;
+                } 
+                
+                final ContentType contentType = ContentType.parse(contentTypeString);
+                if (contentType == null) {
+                    log.warn("HTTP response did not contain a valid content-type");
+                    return null;
+                }            
+                
+                // Is a JWT type or plain JSON object
+                if (ContentType.APPLICATION_JWT.matches(contentType)) {
+                    
+                    try (InputStream input = entity.getContent()) {
+                        final String content = IOUtils.readInputStreamToString(input);
+                        final JWT parsedJwt = JWTParser.parse(content);
+                        return new UserInfoSuccessResponse(parsedJwt);
+                    }
+                    
+                } else if (ContentType.APPLICATION_JSON.matches(contentType)){
+                    
+                    try (InputStream input = entity.getContent()) {
+                        final String content = IOUtils.readInputStreamToString(input);
+                        final Map<String, Object> claims = getObjectMapper().readValue(
+                                content, new TypeReference<Map<String, Object>>() {});
+                        final ClaimsSet claimsSet = new ClaimsSet();
+                        claimsSet.putAll(claims);          
+                        return new UserInfoSuccessResponse(new UserInfo(claimsSet.toJSONObject()));
+                    }
+                } 
+            }
+          
+        } catch (final IllegalArgumentException e) {
+            log.warn("Error creating UserInfo claims set", e);
+            return null;
+        } catch (final Exception e) {
+            log.warn("Unable to decode UserInfo response", e);
+            return null;
+        }
+        log.warn("Unknown UserInfo response type");
+        return null;
+        
+    }
+ // Checkstyle: CyclomaticComplexity|ReturnCount|MethodLength ON
+}
diff --git a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/encoding/impl/UserInfoRequestEncoder.java b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/encoding/impl/UserInfoRequestEncoder.java
new file mode 100644
index 00000000..fa95ada8
--- /dev/null
+++ b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/encoding/impl/UserInfoRequestEncoder.java
@@ -0,0 +1,200 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.profile.encoding.impl;
+
+import java.net.URI;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.NotThreadSafe;
+
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
+import org.apache.hc.core5.net.URIBuilder;
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.messaging.encoder.MessageEncodingException;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
+import org.slf4j.Logger;
+import org.springframework.http.HttpMethod;
+
+import com.nimbusds.jose.util.StandardCharset;
+import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
+import com.nimbusds.openid.connect.sdk.OIDCTokenResponse;
+import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
+
+import net.shibboleth.oidc.profile.config.navigate.UserInfoHttpRequestMethodLookupStrategy;
+import net.shibboleth.oidc.profile.context.AccessTokenResponseContext;
+import net.shibboleth.oidc.profile.oauth2.config.OAuth2AuthorizationProfileConfiguration.HttpRequestMethod;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+/**
+ * Encoder responsible for constructing an HTTP request to the OpenID Connect (OIDC) UserInfo endpoint.
+ * Supports either GET or POST requests.
+ */
+ at NotThreadSafe
+public class UserInfoRequestEncoder extends AbstractRequestEncoderFunction {
+    
+    /** The HTTPS scheme.*/
+    @Nonnull @NotEmpty private static final String HTTPS = "https";
+    
+    /** Class logger. */
+    @Nonnull
+    private final Logger log = LoggerFactory.getLogger(UserInfoRequestEncoder.class);
+    
+    /** Strategy used to look up the {@link AccessTokenResponseContext} to set the parameters for. */
+    @Nonnull private Function<ProfileRequestContext, AccessTokenResponseContext> 
+            tokenResponseContextLookupStrategy;
+   
+    /** Strategy used to look up the {@link HttpMethod} used for this request.*/
+    @Nonnull private Function<ProfileRequestContext, HttpRequestMethod> httpMethodLookupStrategy;
+    
+    /** Constructor.*/
+    public UserInfoRequestEncoder() {
+        tokenResponseContextLookupStrategy =
+                new ChildContextLookup<>(AccessTokenResponseContext.class, true).compose(
+                        new InboundMessageContextLookup());
+        
+        httpMethodLookupStrategy = new UserInfoHttpRequestMethodLookupStrategy();
+    }
+    
+    /**
+     * Set the strategy used to lookup the {@link AccessTokenResponseContext}.
+     * 
+     * @param strategy the strategy
+     */
+    public void setTokenResponseContextLookupStrategy(
+            final Function<ProfileRequestContext, AccessTokenResponseContext> strategy) {
+    	checkSetterPreconditions();
+
+        tokenResponseContextLookupStrategy = Constraint.isNotNull(strategy,
+                "tokenResponseContextLookupStrategy can not be null");
+    }
+    
+    /**
+     * Set the strategy used to lookup the HTTP method to use in this request.
+     * 
+     * @param strategy the strategy
+     */
+    public void setHttpMethodLookupStrategy(final Function<ProfileRequestContext, HttpRequestMethod> strategy) {
+    	checkSetterPreconditions();
+
+        httpMethodLookupStrategy = Constraint.isNotNull(strategy,
+                "httpMethodLookupStrategy can not be null");
+    }
+   
+    
+    @Override
+    @Nullable public ClassicHttpRequest doApply(@Nonnull final ProfileRequestContext profileRequestContext,
+            @Nonnull final OIDCProviderMetadata providerMetadata) {
+        
+        try {
+            final HttpRequestMethod requestMethod = httpMethodLookupStrategy.apply(profileRequestContext);
+            
+            final AccessTokenResponseContext responseCtx = 
+                    tokenResponseContextLookupStrategy.apply(profileRequestContext);
+            if (responseCtx == null) {
+                log.debug("No TokenResponseContext returned by lookup strategy");
+                return null;
+            }            
+            
+            final URI uri = new URIBuilder().setScheme(HTTPS)
+                    .setPort(providerMetadata.getUserInfoEndpointURI().getPort())
+                    .setHost(providerMetadata.getUserInfoEndpointURI().getHost())
+                    .setPath(providerMetadata.getUserInfoEndpointURI().getPath())
+                    .build();                 
+            
+            // Add headers and create request. 
+            ClassicRequestBuilder rb = null;
+            if (requestMethod == HttpRequestMethod.GET) {
+                rb = ClassicRequestBuilder.get().setUri(uri)
+                        .setHeader("Content-Type", ContentType.APPLICATION_FORM_URLENCODED.getMimeType())
+                        .setCharset(StandardCharset.UTF_8);
+                 
+                assert rb != null;
+                addBearerTokenToGet(rb, responseCtx);      
+            } else if (requestMethod == HttpRequestMethod.POST) {
+
+                rb = ClassicRequestBuilder.post().setUri(uri)
+                        .setHeader("Content-Type", ContentType.APPLICATION_FORM_URLENCODED.getMimeType())
+                        .setCharset(StandardCharset.UTF_8);
+
+                assert rb != null;
+                addBearerTokenToPost(rb, responseCtx);   
+            } else {
+                log.error("Unable to construct UserInfo request, unknown request method: {}", requestMethod);
+                return null;
+            }
+
+            final ClassicHttpRequest request = rb.build();                  
+            log.debug("UserInfo request URL '{}'",request);            
+            return request;
+            
+        } catch (final Exception e) {
+            log.warn("Unable to encode token request", e);
+        }
+        return null;
+    }
+    
+    /**
+     * Add the bearer token to the 'access_token' parameter, used when issuing HTTP POST requests.
+     * 
+     * @param rb the request builder to use.
+     * @param responseCtx the response context to find the access_token from.
+     * 
+     * @throws MessageEncodingException if there is an issue adding the bearer token to the 'access_token' parameter.
+     */
+    private void addBearerTokenToPost(@Nonnull final ClassicRequestBuilder rb, 
+        @Nonnull final AccessTokenResponseContext responseCtx) throws MessageEncodingException {
+    
+        final OIDCTokenResponse tokenResponse = responseCtx.getTokenResponse();
+        if (tokenResponse == null) {
+            throw new MessageEncodingException("No access token response found");
+        }
+        final BearerAccessToken bearer = tokenResponse.getTokens().getBearerAccessToken();
+        if (bearer == null) {
+            throw new MessageEncodingException("Access token was not Bearer type");
+        }
+        rb.addParameter("access_token", bearer.getValue());
+    }
+    
+    /** 
+     * Add the bearer token to the Authorization header, used when issuing HTTP GET requests.
+     * 
+     * @param rb the request builder to use.
+     * @param responseCtx the response context to find the access_token from.
+     * 
+     * @throws MessageEncodingException if there is an issue adding the bearer token to the Authorization header.
+     */
+    private void addBearerTokenToGet(@Nonnull final ClassicRequestBuilder rb, 
+            @Nonnull final AccessTokenResponseContext responseCtx) throws MessageEncodingException {
+        
+        final OIDCTokenResponse tokenResponse = responseCtx.getTokenResponse();
+        if (tokenResponse == null) {
+            throw new MessageEncodingException("No access token response found");
+        }
+        final BearerAccessToken bearer = tokenResponse.getTokens().getBearerAccessToken();
+        if (bearer == null) {
+            throw new MessageEncodingException("Access token was not Bearer type");
+        }
+        rb.addHeader("Authorization", bearer.toAuthorizationHeader());        
+    }
+
+
+}

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list