[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