[java-idp-plugin-oidc-rp] branch main updated: Add more functionality

Phil Smart philip.smart at jisc.ac.uk
Thu Feb 3 11:50:28 UTC 2022


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

philsmart pushed a commit to branch main
in repository java-idp-plugin-oidc-rp.

View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-oidc-rp.git;a=commit;h=13839d1415072f63c70a68a99571853b259b2c1d

The following commit(s) were added to refs/heads/main by this push:
     new 13839d1  Add more functionality
13839d1 is described below

commit 13839d1415072f63c70a68a99571853b259b2c1d
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Thu Feb 3 11:50:23 2022 +0000

    Add more functionality
    
     - Add validation for access_token
     - Add id_token validation. Signature and encryption currently not dealt
    with, claims are checked. ACR and nonce checks also missing.
     - Move some classes into commons and update references
---
 .../oidc/rp/AbstractOIDCAuthenticationAction.java  | 149 ---------------
 .../oidc/rp/context/TokenResponseContext.java      |  23 +++
 .../context/OIDCClientMetadataContext.java         |  56 ------
 .../context/OIDCProviderMetadataContext.java       |  47 -----
 .../impl/AbstractRequestEncoderFunction.java       |  14 +-
 .../encoding/impl/DefaultTokenRequestEncoder.java  |   4 +
 .../AbstractOIDCAuthenticationResponseAction.java  |  14 +-
 .../plugin/authn/oidc/rp/impl/AddAuthzRequest.java |  12 +-
 .../oidc/rp/impl/DefaultIDTokenLookupStrategy.java |  50 +++++
 .../rp/impl/DefaultResponseTypeLookupFunction.java |   6 +-
 ...rToken.java => ExchangeCodeForAccessToken.java} |  12 +-
 .../oidc/rp/impl/ExtractIDTokenFromResponse.java   |  66 +++++--
 ...OutboundAuthorizationRequestMessageContext.java |  21 +--
 .../rp/impl/InitializeRelyingPartyContext.java     |   6 +-
 .../impl/ManyValuesIntegerComparisonPredicate.java |  34 +---
 ...viderMetadataFromOuboundPeerLookupStrategy.java |  32 ++++
 .../impl/TokenResponseIDTokenLookupStrategy.java   |  11 +-
 .../rp/impl/ValidateOAuthAccessTokenResponse.java  | 109 +++++++++++
 .../authn/oidc/rp/impl/ValidateTokenClaims.java    |  43 +++--
 .../DefaultClientIDForIssuerLookupFunction.java    |   2 +-
 .../impl/OIDCClientMetadataLookupHandler.java      |   8 +-
 .../impl/OIDCProviderMetadataLookupHandler.java    |  11 +-
 .../oidc-relying-party-authn-beans.xml             | 206 +++++++++++++--------
 .../oidc-relying-party-authn-flow.xml              |  19 +-
 .../impl/DefaultTokenResponseDecoderTest.java      |   2 +-
 .../authn/oidc/rp/impl/AbstractOIDCTest.java       |  14 +-
 .../oidc/rp/impl/ExchangeCodeForTokenTest.java     |   8 +-
 .../rp/impl/ExtractIDTokenFromResponseTest.java    |  71 +++++++
 .../plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java  | 114 ++++++++++--
 .../TokenResponseIDTokenLookupStrategyTest.java    |  74 ++++++++
 30 files changed, 766 insertions(+), 472 deletions(-)

diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/AbstractOIDCAuthenticationAction.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/AbstractOIDCAuthenticationAction.java
deleted file mode 100644
index 1a964e4..0000000
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/AbstractOIDCAuthenticationAction.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements.  See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You 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.idp.plugin.authn.oidc.rp;
-
-import java.util.function.Function;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import org.opensaml.messaging.context.navigate.ChildContextLookup;
-import org.opensaml.profile.action.ActionSupport;
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import net.shibboleth.idp.authn.AbstractAuthenticationAction;
-import net.shibboleth.idp.authn.AuthnEventIds;
-import net.shibboleth.idp.authn.context.AuthenticationContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.context.OpenIDConnectContext;
-import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
-import net.shibboleth.utilities.java.support.component.ComponentSupport;
-import net.shibboleth.utilities.java.support.logic.Constraint;
-
-/**
- * <p>A base class for OIDC authentication related actions.</p>
- * 
- * <p>In addition to the work performed by {@link AbstractAuthenticationAction}, this action also looks up
- * and makes available the {@link OpenIDConnectContext}.</p>
- * 
- * <p>OIDC authentication action implementations should override the
- * {@link #doExecute(ProfileRequestContext, AuthenticationContext, OpenIDConnectContext)} 
- * method.</p>
- * 
- * @event {@link AuthnEventIds#INVALID_AUTHN_CTX}
- * @pre <pre>ProfileRequestContext.getSubcontext(AuthenticationContext.class) != null</pre>
- * @post <pre>AuthenticationContext.getSubcontext(OpenIDConnectContext.class) != null</pre>
- */
-public abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAction {
-    
-    /** Class logger. */
-    @Nonnull @NotEmpty private final Logger log = LoggerFactory.getLogger(AbstractOIDCAuthenticationAction.class);
-    
-    /** Lookup strategy to locate the OIDC authentication context. */
-    @Nonnull private Function<ProfileRequestContext,OpenIDConnectContext> oidcContextLookupStrategy;
-    
-    /** The OIDC authentication Context.*/
-    @Nullable private OpenIDConnectContext oidcContext;
-        
-    
-    /** Constructor.*/
-    protected AbstractOIDCAuthenticationAction() {
-        //prc -> ac -> oidc_context
-        oidcContextLookupStrategy = new ChildContextLookup<>(OpenIDConnectContext.class).
-                compose(new ChildContextLookup<>(AuthenticationContext.class));
-    }
-    
-    
-    /**
-     * Set OIDC authentication context lookup strategy to use.
-     * 
-     * @param strategy lookup strategy
-     */
-    public void setOIDCContextLookupStrategy(
-            @Nonnull final Function<ProfileRequestContext,OpenIDConnectContext> strategy) {
-        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
-
-        oidcContextLookupStrategy = Constraint.isNotNull(strategy, "OIDCContextLookup strategy cannot be null");
-    }
-    
-    /** {@inheritDoc} */
-    @Override
-    protected final boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
-            @Nonnull final AuthenticationContext authenticationContext) {
-
-        if (!super.doPreExecute(profileRequestContext, authenticationContext)) {
-            return false;
-        }
-      
-        oidcContext = oidcContextLookupStrategy.apply(profileRequestContext);
-        if (oidcContext == null) {
-            log.warn("{} No OIDC context returned by lookup strategy",getLogPrefix());
-            ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_AUTHN_CTX);
-            return false;
-            
-        }        
-        
-        return doPreExecute(profileRequestContext, authenticationContext, oidcContext);
-    }
-    
-    /**
-     * Delegates to {@link #doExecute(ProfileRequestContext, AuthenticationContext, 
-     * OpenIDConnectContext)} to perform the actual authentication. Implementations can not 
-     * override this method.
-     * 
-     * @param profileRequestContext the current IdP profile request context
-     * @param authenticationContext the current authentication context
-     */
-    @Override
-    protected final void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
-            @Nonnull final AuthenticationContext authenticationContext) {
-        doExecute(profileRequestContext,authenticationContext,oidcContext);
-    }
-    
-    /**
-     * Performs this authentication action's pre-execute step. Default implementation just returns true.
-     * 
-     * @param profileRequestContext the current IdP profile request context
-     * @param authenticationContext the current authentication context
-     * @param context the OIDC authentication context
-     * 
-     * @return true iff execution should continue
-     */
-    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
-            @Nonnull final AuthenticationContext authenticationContext,
-            @Nonnull final OpenIDConnectContext context) {
-        return true;
-    }
-    
-    /**
-     * Performs this OIDC authentication action using the supplied OIDC context. Implementations
-     * should override this method.
-     * 
-     * @param profileRequestContext the current IdP profile request context
-     * @param authenticationContext the current authentication context
-     * @param context the OIDC authentication context
-     */
-    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
-            @Nonnull final AuthenticationContext authenticationContext,
-            @Nonnull final OpenIDConnectContext context) {
-        
-    }
-
-}
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/TokenResponseContext.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/TokenResponseContext.java
index 56a78d8..104db77 100644
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/TokenResponseContext.java
+++ b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/TokenResponseContext.java
@@ -23,12 +23,17 @@ import javax.annotation.Nullable;
 
 import org.opensaml.messaging.context.BaseContext;
 
+import com.nimbusds.jwt.JWT;
+
 /** A context to hold an OIDC token request response.*/
 public class TokenResponseContext extends BaseContext {
     
     /** The raw token response as a map.*/
     @Nullable private Map<String, Object> rawTokenResponse;
     
+    /** The id_token, should match that in the rawTokenResponse if one exists.*/
+    @Nullable private JWT idToken;
+    
     /**
      * Set the raw token response as a map.
      * 
@@ -46,5 +51,23 @@ public class TokenResponseContext extends BaseContext {
     @Nullable public Map<String, Object> getRawTokenResponse() {
         return rawTokenResponse;
     }
+    
+    /**
+     * Set the id_token.
+     * 
+     * @param token the id_token.
+     */
+    public void setIdToken(@Nullable final JWT token) {
+        idToken = token;
+    }
+    
+    /**
+     * Get the id_token.
+     * 
+     * @return the id_token.
+     */
+    @Nullable public JWT getIdToken() {
+        return idToken;
+    }
 
 }
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/messaging/context/OIDCClientMetadataContext.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/messaging/context/OIDCClientMetadataContext.java
deleted file mode 100644
index f0b9f5b..0000000
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/messaging/context/OIDCClientMetadataContext.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements.  See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You 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.idp.plugin.authn.oidc.rp.messaging.context;
-
-import javax.annotation.Nullable;
-
-import org.opensaml.messaging.context.BaseContext;
-
-import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
-
-/**
- * Subcontext carrying information on metadata of the relying party. This
- * context appears as a subcontext of the
- * {@link org.opensaml.messaging.context.MessageContext} that carries the actual
- * OIDC request message, in such cases the metadata carried herein applies to
- * the issuer of that message.
- */
-public class OIDCClientMetadataContext extends BaseContext {
-
-    /** The client information. */
-    @Nullable private OIDCClientInformation clientInformation;
-    
-    /**
-     * Set the client information.
-     * 
-     * @return The client information.
-     */
-    @Nullable
-    public OIDCClientInformation getClientInformation() {
-        return clientInformation;
-    }
-
-    /**
-     * Set the client information.
-     * 
-     * @param information The client information.
-     */
-    public void setClientInformation(@Nullable final OIDCClientInformation information) {
-        clientInformation = information;
-    }
-}
\ No newline at end of file
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/messaging/context/OIDCProviderMetadataContext.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/messaging/context/OIDCProviderMetadataContext.java
deleted file mode 100644
index 849edac..0000000
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/messaging/context/OIDCProviderMetadataContext.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.ThreadSafe;
-
-import org.opensaml.messaging.context.BaseContext;
-
-import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
-
-import net.shibboleth.utilities.java.support.logic.Constraint;
-
-/**
- * Subcontext carrying information on metadata of the openid provider. This
- * context appears as a subcontext of the
- * {@link org.opensaml.messaging.context.MessageContext} that carries the actual
- * OIDC request message, in such cases the metadata carried herein applies to
- * the issuer of that message.
- */
- at ThreadSafe
-public class OIDCProviderMetadataContext extends BaseContext {
-
-    /** The client information. */
-    @Nonnull private final OIDCProviderMetadata providerInformation;
-    
-    /**
-     * 
-     * Constructor.
-     *
-     * @param metadata the provider configuration information.
-     */
-    //TODO not sure this is needed in constructor, make inline with other contexts.
-    public OIDCProviderMetadataContext(@Nonnull final OIDCProviderMetadata metadata) {
-        providerInformation = Constraint.isNotNull(metadata, "OIDC Provider Metadata can not be null");
-    }
-    
-    /**
-     * Set the client information.
-     * 
-     * @return The client information.
-     */
-    @Nullable
-    public OIDCProviderMetadata getProviderInformation() {
-        return providerInformation;
-    }
-
-}
\ No newline at end of file
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/encoding/impl/AbstractRequestEncoderFunction.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/encoding/impl/AbstractRequestEncoderFunction.java
index bf4baa5..30fd576 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/encoding/impl/AbstractRequestEncoderFunction.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/encoding/impl/AbstractRequestEncoderFunction.java
@@ -33,8 +33,8 @@ import org.slf4j.LoggerFactory;
 import com.nimbusds.openid.connect.sdk.AuthenticationSuccessResponse;
 
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCProviderMetadataContext;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
 import net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest;
 import net.shibboleth.utilities.java.support.component.AbstractInitializableComponent;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
@@ -52,7 +52,7 @@ public abstract class AbstractRequestEncoderFunction extends AbstractInitializab
     @Nonnull private Function<ProfileRequestContext, OIDCProviderMetadataContext> providerMetadataLookupStrategy;
     
     /** Lookup strategy to locate the metadata of the client to use to communicate with the OP.*/
-    @Nonnull private Function<ProfileRequestContext,OIDCClientMetadataContext> clientMetadataLookupStrategy;
+    @Nonnull private Function<ProfileRequestContext,OIDCMetadataContext> clientMetadataLookupStrategy;
 
     /** OIDC authentication response from downstream OP. */
     @Nullable private AuthenticationSuccessResponse authnResponse;
@@ -61,7 +61,7 @@ public abstract class AbstractRequestEncoderFunction extends AbstractInitializab
     @Nullable private OIDCAuthenticationRequest authnRequest;
 
     /** OIDC client Metadata context. */
-    @Nullable private OIDCClientMetadataContext clientMetadataContext;
+    @Nullable private OIDCMetadataContext clientMetadataContext;
     
     /** OIDC Metadata context. */
     @Nullable private OIDCProviderMetadataContext providerMetadataContext;
@@ -72,7 +72,7 @@ public abstract class AbstractRequestEncoderFunction extends AbstractInitializab
                 new ChildContextLookup<>(OIDCPeerEntityContext.class).compose(
                         new OutboundMessageContextLookup()));
         
-        clientMetadataLookupStrategy = new ChildContextLookup<>(OIDCClientMetadataContext.class).compose(
+        clientMetadataLookupStrategy = new ChildContextLookup<>(OIDCMetadataContext.class).compose(
                 new OutboundMessageContextLookup());
     }
     
@@ -95,7 +95,7 @@ public abstract class AbstractRequestEncoderFunction extends AbstractInitializab
      * @param strategy the strategy.
      */
     public void setClientMetadataLookupStrategy(
-            @Nonnull final Function<ProfileRequestContext, OIDCClientMetadataContext> strategy) {
+            @Nonnull final Function<ProfileRequestContext, OIDCMetadataContext> strategy) {
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
         
         clientMetadataLookupStrategy = Constraint.isNotNull(strategy,"Client metadata lookup strategy can not be null");
@@ -124,7 +124,7 @@ public abstract class AbstractRequestEncoderFunction extends AbstractInitializab
      * 
      * @return The client metadata context.
      */
-    @Nullable public OIDCClientMetadataContext getClientMetadataContext() {
+    @Nullable public OIDCMetadataContext getClientMetadataContext() {
         return clientMetadataContext;
     }
     
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/encoding/impl/DefaultTokenRequestEncoder.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/encoding/impl/DefaultTokenRequestEncoder.java
index 797306f..3da272e 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/encoding/impl/DefaultTokenRequestEncoder.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/encoding/impl/DefaultTokenRequestEncoder.java
@@ -52,6 +52,10 @@ public class DefaultTokenRequestEncoder extends AbstractRequestEncoderFunction {
     @Nullable public HttpUriRequest doApply(@Nonnull final ProfileRequestContext profileRequestContext) {
 
         try {
+            if (getClientMetadataContext().getClientInformation() == null) {
+                log.warn("No client information present to base token request off");
+                return null;
+            }
             // Mandate HTTPS, so construct the URL from that.
             final URI uri = new URIBuilder().setScheme(HTTPS)
                     .setHost(getProviderMetadataContext()
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCAuthenticationResponseAction.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCAuthenticationResponseAction.java
index d7b4d9d..83d8dc8 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCAuthenticationResponseAction.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCAuthenticationResponseAction.java
@@ -37,8 +37,8 @@ import com.nimbusds.openid.connect.sdk.AuthenticationSuccessResponse;
 import net.shibboleth.idp.authn.AbstractAuthenticationAction;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCProviderMetadataContext;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
 import net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -61,7 +61,7 @@ abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAc
     @Nonnull private Function<ProfileRequestContext, OIDCProviderMetadataContext> providerMetadataLookupStrategy;
     
     /** Lookup strategy to locate the metadata of the client to use to communicate with the OP.*/
-    @Nonnull private Function<ProfileRequestContext,OIDCClientMetadataContext> clientMetadataLookupStrategy;
+    @Nonnull private Function<ProfileRequestContext,OIDCMetadataContext> clientMetadataLookupStrategy;
 
     /** OIDC authentication response from downstream OP. */
     @Nullable private AuthenticationSuccessResponse authnResponse;
@@ -70,7 +70,7 @@ abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAc
     @Nullable private OIDCAuthenticationRequest authnRequest;
 
     /** OIDC client Metadata context. */
-    @Nullable private OIDCClientMetadataContext clientMetadataContext;
+    @Nullable private OIDCMetadataContext clientMetadataContext;
     
     /** OIDC Metadata context. */
     @Nullable private OIDCProviderMetadataContext providerMetadataContext;
@@ -81,7 +81,7 @@ abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAc
                 new ChildContextLookup<>(OIDCPeerEntityContext.class).compose(
                         new OutboundMessageContextLookup()));
         
-        clientMetadataLookupStrategy = new ChildContextLookup<>(OIDCClientMetadataContext.class).compose(
+        clientMetadataLookupStrategy = new ChildContextLookup<>(OIDCMetadataContext.class).compose(
                 new OutboundMessageContextLookup());
     }
     
@@ -104,7 +104,7 @@ abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAc
      * @param strategy the strategy.
      */
     public void setClientMetadataLookupStrategy(
-            @Nonnull final Function<ProfileRequestContext, OIDCClientMetadataContext> strategy) {
+            @Nonnull final Function<ProfileRequestContext, OIDCMetadataContext> strategy) {
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
         
         clientMetadataLookupStrategy = Constraint.isNotNull(strategy,"Client metadata lookup strategy can not be null");
@@ -133,7 +133,7 @@ abstract class AbstractOIDCAuthenticationAction extends AbstractAuthenticationAc
      * 
      * @return The client metadata context.
      */
-    @Nullable public OIDCClientMetadataContext getClientMetadataContext() {
+    @Nullable public OIDCMetadataContext getClientMetadataContext() {
         return clientMetadataContext;
     }
     
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddAuthzRequest.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddAuthzRequest.java
index 871c634..8049654 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddAuthzRequest.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AddAuthzRequest.java
@@ -37,10 +37,10 @@ import net.shibboleth.idp.authn.AbstractAuthenticationAction;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.ResponseTypeAndModeContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCProviderMetadataContext;
 import net.shibboleth.idp.profile.IdPEventIds;
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
 import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
 import net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
@@ -72,7 +72,7 @@ public class AddAuthzRequest extends AbstractAuthenticationAction {
     @Nullable private OIDCAuthorizationConfiguration profileConfiguration;
     
     /** The metadata belonging to the client registered with the current OpenID Provider.*/
-    @Nullable private OIDCClientMetadataContext clientMetadata;
+    @Nullable private OIDCMetadataContext clientMetadata;
     
     /** The metadata belonging to the OpenID Provider.*/
     @Nullable private OIDCProviderMetadataContext providerMetadata;
@@ -84,7 +84,7 @@ public class AddAuthzRequest extends AbstractAuthenticationAction {
     @Nonnull private Function<ProfileRequestContext, OIDCProviderMetadataContext> providerMetadataLookupStrategy;
     
     /** Lookup strategy to locate the metadata of the client to use to communicate with the OP.*/
-    @Nonnull private Function<ProfileRequestContext,OIDCClientMetadataContext> clientMetadataLookupStrategy;
+    @Nonnull private Function<ProfileRequestContext,OIDCMetadataContext> clientMetadataLookupStrategy;
     
     /** Lookup strategy to locate the response_mode and response_type context.*/
     @Nonnull private Function<ProfileRequestContext,ResponseTypeAndModeContext> responseTypeAndModeLookupStrategy;
@@ -98,7 +98,7 @@ public class AddAuthzRequest extends AbstractAuthenticationAction {
                 new ChildContextLookup<>(OIDCPeerEntityContext.class).compose(
                         new InboundMessageContextLookup()));
         
-        clientMetadataLookupStrategy = new ChildContextLookup<>(OIDCClientMetadataContext.class).compose(
+        clientMetadataLookupStrategy = new ChildContextLookup<>(OIDCMetadataContext.class).compose(
                 new InboundMessageContextLookup());
         
         responseTypeAndModeLookupStrategy = new ChildContextLookup<>(ResponseTypeAndModeContext.class).compose(
@@ -124,7 +124,7 @@ public class AddAuthzRequest extends AbstractAuthenticationAction {
      * @param strategy the strategy.
      */
     public void setClientMetadataLookupStrategy(
-            @Nonnull final Function<ProfileRequestContext, OIDCClientMetadataContext> strategy) {
+            @Nonnull final Function<ProfileRequestContext, OIDCMetadataContext> strategy) {
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
         
         clientMetadataLookupStrategy = Constraint.isNotNull(strategy,"Client metadata lookup strategy can not be null");
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultIDTokenLookupStrategy.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultIDTokenLookupStrategy.java
new file mode 100644
index 0000000..ddad58f
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultIDTokenLookupStrategy.java
@@ -0,0 +1,50 @@
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
+
+import com.nimbusds.jwt.JWT;
+
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.TokenResponseContext;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/** Function that extracts the id_token from the {@link TokenResponseContext}.*/
+public class DefaultIDTokenLookupStrategy implements Function<ProfileRequestContext, JWT> {
+    
+    /** Strategy used to locate the TokenResponseContext to extract the id_token from.*/
+    @Nonnull private Function<ProfileRequestContext, TokenResponseContext> tokenResponseContextLookupStrategy;
+    
+    /** Constructor.*/
+    public DefaultIDTokenLookupStrategy() {
+        tokenResponseContextLookupStrategy =
+                new ChildContextLookup<>(TokenResponseContext.class, true).compose(
+                        new InboundMessageContextLookup()); 
+    }
+    
+    /**
+     * Set the strategy used to look up a {@link TokenResponseContext}.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setTokenResponseContextLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext, TokenResponseContext> strategy) {        
+        tokenResponseContextLookupStrategy = Constraint.isNotNull(strategy,
+                "TokenResponseContext lookup strategy cannot be null");
+    }
+
+    @Override
+    @Nullable public JWT apply(@Nonnull final ProfileRequestContext prc) {
+        final TokenResponseContext tokenContext = tokenResponseContextLookupStrategy.apply(prc);
+        if (tokenContext == null) {
+            return null;
+        }
+        return tokenContext.getIdToken();
+    }
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultResponseTypeLookupFunction.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultResponseTypeLookupFunction.java
index e08eacf..f2f5eaf 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultResponseTypeLookupFunction.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultResponseTypeLookupFunction.java
@@ -29,7 +29,7 @@ import org.slf4j.LoggerFactory;
 
 import com.nimbusds.oauth2.sdk.ResponseType;
 
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
 
 /**
  * A lookup function that returns a response_type from the 'first' described in a client's metadata. 
@@ -52,8 +52,8 @@ public class DefaultResponseTypeLookupFunction implements Function<ProfileReques
         }
         
         final MessageContext inboundMessageCtx = profileRequestContext.getInboundMessageContext();
-        final OIDCClientMetadataContext clientMetadataCtx = 
-                inboundMessageCtx.getSubcontext(OIDCClientMetadataContext.class);
+        final OIDCMetadataContext clientMetadataCtx = 
+                inboundMessageCtx.getSubcontext(OIDCMetadataContext.class);
         if (clientMetadataCtx != null &&
                 clientMetadataCtx.getClientInformation() != null &&
                     clientMetadataCtx.getClientInformation().getOIDCMetadata() != null &&
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForToken.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForAccessToken.java
similarity index 95%
rename from idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForToken.java
rename to idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForAccessToken.java
index 2fc953d..b71ce90 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForToken.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForAccessToken.java
@@ -42,8 +42,8 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
 
 
 /**
- * Action to exchange the authorization code in the authentication response for a token response which 
- * contains an id_token. Once obtained, adds the token to the {@link TokenResponseContext}.
+ * Action to exchange the authorization code in the authentication response for an OAuth access token which 
+ * contains an OIDC id_token. Once obtained, adds the token to the {@link TokenResponseContext}.
  * 
  * FIXME: these conditions
  * 
@@ -54,10 +54,10 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
  * AuthenticationContext.getSubcontect(DuoOIDCAuthenticationContext.class,false)!=null</pre>
  * @post Add the Duo authentication token to the context. 
  */
-public class ExchangeCodeForToken extends AbstractHttpOIDCAuthenticationAction {
+public class ExchangeCodeForAccessToken extends AbstractHttpOIDCAuthenticationAction {
     
     /** Class logger.*/
-    @Nonnull private final Logger log = LoggerFactory.getLogger(ExchangeCodeForToken.class);
+    @Nonnull private final Logger log = LoggerFactory.getLogger(ExchangeCodeForAccessToken.class);
     
     /** The message encoder to use encode the token request into a HttpRequest.*/
     @NonnullAfterInit private Function<ProfileRequestContext, HttpUriRequest> tokenRequestEncoderStrategy;
@@ -70,7 +70,7 @@ public class ExchangeCodeForToken extends AbstractHttpOIDCAuthenticationAction {
             tokenResponseContextLookupStrategy;
     
     /** Constructor.*/
-    public ExchangeCodeForToken() {
+    public ExchangeCodeForAccessToken() {
         tokenResponseContextLookupStrategy =
                 new ChildContextLookup<>(TokenResponseContext.class, true).compose(
                         new InboundMessageContextLookup());
@@ -114,7 +114,7 @@ public class ExchangeCodeForToken extends AbstractHttpOIDCAuthenticationAction {
         
         tokenRequestEncoderStrategy = Constraint.isNotNull(strategy, "Token encoder strategy can not be null");
     }
-    
+      
     
     @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) { 
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExtractIDTokenFromResponse.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExtractIDTokenFromResponse.java
index c286ec7..d76f4d8 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExtractIDTokenFromResponse.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExtractIDTokenFromResponse.java
@@ -22,8 +22,11 @@ import java.util.function.Function;
 
 import javax.annotation.Nonnull;
 
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
 import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -31,7 +34,11 @@ import com.nimbusds.jose.JOSEObject;
 import com.nimbusds.jose.JWEObject;
 import com.nimbusds.jose.JWSObject;
 import com.nimbusds.jose.PlainObject;
+import com.nimbusds.jwt.EncryptedJWT;
+import com.nimbusds.jwt.PlainJWT;
+import com.nimbusds.jwt.SignedJWT;
 
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.TokenResponseContext;
 import net.shibboleth.idp.profile.AbstractProfileAction;
 import net.shibboleth.oidc.profile.core.OidcEventIds;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
@@ -39,7 +46,7 @@ import net.shibboleth.utilities.java.support.component.ComponentInitializationEx
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 
-/** Action that extracts and id_token from the inbound message context and sets it onto a TODO context.*/
+/** Action that extracts an id_token from the inbound message context and sets it onto a TODO context.*/
 public class ExtractIDTokenFromResponse extends AbstractProfileAction {
 
     /** Class logger. */
@@ -48,6 +55,33 @@ public class ExtractIDTokenFromResponse extends AbstractProfileAction {
     /** Function that looks up a raw id_token value as a base64 encoded string.*/
     @NonnullAfterInit private Function<ProfileRequestContext, String> rawIdTokenLookupStrategy;
     
+    /** The token response context to add the decoded id_token too.*/
+    @NonnullAfterInit private TokenResponseContext responseCtx;
+    
+    /** Strategy used to look up the {@link TokenResponseContext} to set the parameters for. */
+    @Nonnull private Function<ProfileRequestContext, TokenResponseContext> 
+            tokenResponseContextLookupStrategy;
+    
+    /** Constructor.*/
+    public ExtractIDTokenFromResponse() {
+        tokenResponseContextLookupStrategy =
+                new ChildContextLookup<>(TokenResponseContext.class).compose(
+                        new InboundMessageContextLookup());
+    }
+    
+    /**
+     * Set the strategy used to look up a {@link TokenResponseContext}.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setTokenResponseContextLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext, TokenResponseContext> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        tokenResponseContextLookupStrategy = Constraint.isNotNull(strategy,
+                "TokenResponseContext lookup strategy cannot be null");
+    }
+    
     @Override
     protected void doInitialize() throws ComponentInitializationException {
         super.doInitialize();
@@ -56,7 +90,19 @@ public class ExtractIDTokenFromResponse extends AbstractProfileAction {
             throw new ComponentInitializationException("RawIdTokenLookupStrategy cannot be null");
         }
     }
-
+    
+    @Override protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        
+        responseCtx = tokenResponseContextLookupStrategy.apply(profileRequestContext);
+        if (responseCtx == null) {
+            log.debug("{} No TokenResponseContext returned by lookup strategy", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+            return false;
+        }
+        return true;
+    }
+    
+    
     /**
      * Set the strategy used to lookup a base64 encoded JWT from the profile request context.
      *
@@ -69,11 +115,6 @@ public class ExtractIDTokenFromResponse extends AbstractProfileAction {
         rawIdTokenLookupStrategy = Constraint.isNotNull(strategy,"Raw id_token lookup strategy can not be null");
     }
     
-    @Override protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
-        
-        return true;
-    }
-    
     @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
         
         final String rawIdTokenValue = rawIdTokenLookupStrategy.apply(profileRequestContext);
@@ -82,23 +123,22 @@ public class ExtractIDTokenFromResponse extends AbstractProfileAction {
             ActionSupport.buildEvent(profileRequestContext,OidcEventIds.INVALID_ID_TOKEN);
             return;
         }
-        log.trace("{} Base64 encoded id_token is '{}'",getLogPrefix(), rawIdTokenValue);
+        log.trace("{} (Assumed) Base64 encoded id_token is '{}'",getLogPrefix(), rawIdTokenValue);
         try {
             final JOSEObject joseObject = JOSEObject.parse(rawIdTokenValue);
             log.trace("{} Parsed JOSE Object '{}'",getLogPrefix(), joseObject);
             if (joseObject instanceof PlainObject) {
-                final PlainObject plainObject = (PlainObject)joseObject;
+                responseCtx.setIdToken(PlainJWT.parse(rawIdTokenValue));
                 
             } else if (joseObject instanceof JWSObject) {
-                final JWSObject jwsObject = (JWSObject)joseObject;
+                responseCtx.setIdToken(SignedJWT.parse(rawIdTokenValue));
                 
             } else if (joseObject instanceof JWEObject) {
-                final JWEObject jweObject = (JWEObject)joseObject;
-                
+                responseCtx.setIdToken(EncryptedJWT.parse(rawIdTokenValue));
             }
             
         } catch (final ParseException e) {
-            log.warn("{}: Unable to parse id_token",getLogPrefix(), e);
+            log.warn("{} Unable to parse id_token",getLogPrefix(), e);
             ActionSupport.buildEvent(profileRequestContext,OidcEventIds.INVALID_ID_TOKEN);
             return;
             
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeOutboundAuthorizationRequestMessageContext.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeOutboundAuthorizationRequestMessageContext.java
index 0141ca1..692d844 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeOutboundAuthorizationRequestMessageContext.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeOutboundAuthorizationRequestMessageContext.java
@@ -33,11 +33,11 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCProviderMetadataContext;
 import net.shibboleth.idp.profile.AbstractProfileAction;
 import net.shibboleth.idp.profile.IdPEventIds;
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 
@@ -51,10 +51,10 @@ public class InitializeOutboundAuthorizationRequestMessageContext extends Abstra
     /** The {@link OIDCPeerEntityContext} to base the outbound context on. */
     @Nullable private OIDCPeerEntityContext peerEntityCtx;
         
-    /** Strategy function to lookup the {@link OIDCClientMetadataContext} that represents this client during
+    /** Strategy function to lookup the {@link OIDCMetadataContext} that represents this client during
      * communication with the given OIDC peer. */
     @Nonnull 
-    private Function<ProfileRequestContext, OIDCClientMetadataContext> oidcClientMetadataCtxLookupStrategy;
+    private Function<ProfileRequestContext, OIDCMetadataContext> oidcClientMetadataCtxLookupStrategy;
     
     /**
      * Strategy used to locate the {@link RelyingPartyContext} associated with a given {@link ProfileRequestContext}.
@@ -66,7 +66,7 @@ public class InitializeOutboundAuthorizationRequestMessageContext extends Abstra
      * Constructor.
      */
     public InitializeOutboundAuthorizationRequestMessageContext() {
-        oidcClientMetadataCtxLookupStrategy = new ChildContextLookup<>(OIDCClientMetadataContext.class).compose(
+        oidcClientMetadataCtxLookupStrategy = new ChildContextLookup<>(OIDCMetadataContext.class).compose(
                 new InboundMessageContextLookup());    
         relyingPartyCtxLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
     }
@@ -78,7 +78,7 @@ public class InitializeOutboundAuthorizationRequestMessageContext extends Abstra
      * @param strgy What to set.
      */
     public void setOIDCClientMetadataContextLookupStrategy(
-            @Nonnull final Function<ProfileRequestContext, OIDCClientMetadataContext> strgy) {
+            @Nonnull final Function<ProfileRequestContext, OIDCMetadataContext> strgy) {
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
 
         oidcClientMetadataCtxLookupStrategy = Constraint.isNotNull(strgy, "Injected Metadata Strategy cannot be null");
@@ -141,16 +141,15 @@ public class InitializeOutboundAuthorizationRequestMessageContext extends Abstra
         if (inboundProviderMetadata != null) {
             
             // Pass a reference here? we do not need to mutate the metadata
-            final OIDCProviderMetadataContext outMetadata = 
-                    new OIDCProviderMetadataContext(inboundProviderMetadata.getProviderInformation());
-            
+            final OIDCProviderMetadataContext outMetadata = new OIDCProviderMetadataContext();
+            outMetadata.setProviderInformation(inboundProviderMetadata.getProviderInformation());              
             outboundPeerContext.addSubcontext(outMetadata);
             
         }
-        final OIDCClientMetadataContext inboundClientMetadata = 
+        final OIDCMetadataContext inboundClientMetadata = 
                 oidcClientMetadataCtxLookupStrategy.apply(profileRequestContext);
         
-        final OIDCClientMetadataContext outboundClientMetadata = new OIDCClientMetadataContext();
+        final OIDCMetadataContext outboundClientMetadata = new OIDCMetadataContext();
         outboundClientMetadata.setClientInformation(inboundClientMetadata.getClientInformation());
         msgCtx.addSubcontext(outboundClientMetadata);
 
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeRelyingPartyContext.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeRelyingPartyContext.java
index ac3bc54..4d1be9d 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeRelyingPartyContext.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeRelyingPartyContext.java
@@ -32,11 +32,11 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCProviderMetadataContext;
 import net.shibboleth.idp.profile.AbstractProfileAction;
 import net.shibboleth.idp.profile.IdPEventIds;
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 
@@ -58,7 +58,7 @@ public class InitializeRelyingPartyContext extends AbstractProfileAction {
     /** Strategy that will return or create a {@link RelyingPartyContext}. */
     @Nonnull private Function<ProfileRequestContext, RelyingPartyContext> relyingPartyContextCreationStrategy;
     
-    /** Strategy that will return {@link OIDCClientMetadataContext}. */
+    /** Strategy that will return {@link OIDCMetadataContext}. */
     @Nonnull 
     private Function<ProfileRequestContext, OIDCProviderMetadataContext> oidcProviderMetadataContextLookupStrategy;
         
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/TokenResponseContext.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ManyValuesIntegerComparisonPredicate.java
similarity index 50%
copy from idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/TokenResponseContext.java
copy to idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ManyValuesIntegerComparisonPredicate.java
index 56a78d8..eff2379 100644
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/TokenResponseContext.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ManyValuesIntegerComparisonPredicate.java
@@ -15,36 +15,16 @@
  * limitations under the License.
  */
 
-package net.shibboleth.idp.plugin.authn.oidc.rp.context;
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
 
-import java.util.Map;
+import java.util.function.IntPredicate;
 
-import javax.annotation.Nullable;
+/** Predicate that returns true if the test integer is greater than 1.*/
+public class ManyValuesIntegerComparisonPredicate implements IntPredicate {
 
-import org.opensaml.messaging.context.BaseContext;
-
-/** A context to hold an OIDC token request response.*/
-public class TokenResponseContext extends BaseContext {
-    
-    /** The raw token response as a map.*/
-    @Nullable private Map<String, Object> rawTokenResponse;
-    
-    /**
-     * Set the raw token response as a map.
-     * 
-     * @param rawResponse the raw response.
-     */
-    public void setRawTokenResponse(@Nullable final Map<String, Object> rawResponse) {
-        rawTokenResponse = rawResponse;
-    }
-    
-    /**
-     * Get the raw token response map.
-     * 
-     * @return the raw response map.
-     */
-    @Nullable public Map<String, Object> getRawTokenResponse() {
-        return rawTokenResponse;
+    @Override
+    public boolean test(final int value) {
+        return value > 1;
     }
 
 }
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCProviderMetadataFromOuboundPeerLookupStrategy.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCProviderMetadataFromOuboundPeerLookupStrategy.java
new file mode 100644
index 0000000..85c0812
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCProviderMetadataFromOuboundPeerLookupStrategy.java
@@ -0,0 +1,32 @@
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
+
+/** 
+ * Lookup function to extract the {@link OIDCProviderMetadataContext} from the {@link OIDCPeerEntityContext} in the
+ * outbound message.
+ */
+public class OIDCProviderMetadataFromOuboundPeerLookupStrategy 
+                    implements Function<ProfileRequestContext, OIDCProviderMetadataContext>{
+
+    @Override
+    @Nullable public OIDCProviderMetadataContext apply(@Nonnull final ProfileRequestContext prc) {
+        if (prc.getOutboundMessageContext() == null) {
+            return null;
+        }
+        if (prc.getOutboundMessageContext().getSubcontext(OIDCPeerEntityContext.class) == null) {
+            return null;
+        }
+        return prc.getOutboundMessageContext()
+                .getSubcontext(OIDCPeerEntityContext.class).getSubcontext(OIDCProviderMetadataContext.class);
+    }
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TokenResponseIDTokenLookupStrategy.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TokenResponseIDTokenLookupStrategy.java
index 5edd244..49e7b63 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TokenResponseIDTokenLookupStrategy.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TokenResponseIDTokenLookupStrategy.java
@@ -24,21 +24,28 @@ import javax.annotation.Nullable;
 
 import org.opensaml.messaging.context.MessageContext;
 import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.TokenResponseContext;
 
-/** Return the base64 encoded id_token from the TokenResponseContext, or null if not found.*/
+/** Return the raw base64 encoded id_token from the TokenResponseContext, or null if not found.*/
 public class TokenResponseIDTokenLookupStrategy implements Function<ProfileRequestContext, String> {
+    
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(TokenResponseIDTokenLookupStrategy.class);
 
     @Override
     @Nullable public String apply(@Nonnull final ProfileRequestContext profileRequestContext) {
         
         final MessageContext inbound = profileRequestContext.getInboundMessageContext();
         if (inbound == null) {
+            log.debug("Inbound message context was null, no id_token found");
             return null;
         }
         final TokenResponseContext tokenResponseContext = inbound.getSubcontext(TokenResponseContext.class);
         if (tokenResponseContext == null) {
+            log.debug("Token response context was null, no id_token found");
             return null;
         }
         if (tokenResponseContext.getRawTokenResponse() != null) {
@@ -46,7 +53,9 @@ public class TokenResponseIDTokenLookupStrategy implements Function<ProfileReque
             if (idTokenObject instanceof String) {
                 return (String) idTokenObject;
             }
+            log.debug("Token response was not a string, no id_token found");
         }
+        log.debug("Raw token response was null, no id_token found");
         return null;
         
     }
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateOAuthAccessTokenResponse.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateOAuthAccessTokenResponse.java
new file mode 100644
index 0000000..f442388
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateOAuthAccessTokenResponse.java
@@ -0,0 +1,109 @@
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import java.util.Map;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventIds;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.TokenResponseContext;
+import net.shibboleth.oidc.profile.core.OidcEventIds;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/** Validation action that validates the OAuth Access Token Response against RFC 6749 section 5.1
+ * and OpenID Connect Core 1.0 section 3.1.3.3.*/
+public class ValidateOAuthAccessTokenResponse extends AbstractOIDCAuthenticationAction {    
+    
+    /** Class logger. */    
+    @Nonnull @NotEmpty private final Logger log = LoggerFactory.getLogger(ValidateOAuthAccessTokenResponse.class); 
+    
+    /** Strategy used to look up the {@link TokenResponseContext} to validate. */
+    @Nonnull private Function<ProfileRequestContext, TokenResponseContext> 
+            tokenResponseContextLookupStrategy;
+    
+    /** Constructor.*/
+    public ValidateOAuthAccessTokenResponse() {
+        tokenResponseContextLookupStrategy =
+                new ChildContextLookup<>(TokenResponseContext.class, true).compose(
+                        new InboundMessageContextLookup());
+    }
+    
+    /**
+     * Set the strategy used to look up a {@link TokenResponseContext}.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setTokenResponseContextLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext, TokenResponseContext> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        tokenResponseContextLookupStrategy = Constraint.isNotNull(strategy,
+                "TokenResponseContext lookup strategy cannot be null");
+    }
+    
+    /** {@inheritDoc} */
+    @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
+            @Nonnull final AuthenticationContext authenticationContext) {
+        
+        final TokenResponseContext responseCtx = tokenResponseContextLookupStrategy.apply(profileRequestContext);
+        if (responseCtx == null) {
+            log.debug("{} No TokenResponseContext returned by lookup strategy", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+            return;
+        }
+        final Map<String, Object> rawTokenResponse = responseCtx.getRawTokenResponse();
+        if (rawTokenResponse == null) {
+            log.debug("{} No access token response found, response invalid", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_ACCESS_TOKEN);
+            return;
+        }
+        // Look for an error response. This may never get here depending on the upflow response decoder used.
+        if (rawTokenResponse.containsKey("error")) {
+            log.debug("{} Error response found instead of access token, error is '{}'", getLogPrefix(),
+                    rawTokenResponse.get("error"));
+            ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_ACCESS_TOKEN);
+            return;
+        }
+        // Otherwise check is valid success response
+        if (!rawTokenResponse.containsKey("access_token")) {
+            log.warn("{} Access token response is invalid, no access_token found", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_ACCESS_TOKEN);
+            return;
+        }
+        if (!rawTokenResponse.containsKey("token_type")) {
+            log.warn("{} Access token response is invalid, no token_type found", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_ACCESS_TOKEN);
+            return;
+        } else {
+            // Only support Bearer type
+            final Object tokenTypeObject = rawTokenResponse.get("token_type");
+            if (tokenTypeObject instanceof String) {
+                if (!"Bearer".equals((String)tokenTypeObject)) {
+                    log.warn("{} Access token response is invalid, bearer token_type required", getLogPrefix());
+                    ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_ACCESS_TOKEN);
+                    return;
+                }
+            } else {
+                log.warn("{} Access token response is invalid, bearer token_type required", getLogPrefix());
+                ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_ACCESS_TOKEN);
+                return;
+            }
+        }
+        if (!rawTokenResponse.containsKey("expires_in")) {
+            log.trace("{} Expires_in not found in access token, is recomended ", getLogPrefix());
+        }
+
+        
+    }
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateTokenClaims.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateTokenClaims.java
index 3b4d560..a740a3d 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateTokenClaims.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateTokenClaims.java
@@ -2,6 +2,7 @@ package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
 
 import java.text.ParseException;
 import java.util.function.Consumer;
+import java.util.function.Function;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -16,10 +17,9 @@ import com.nimbusds.jwt.JWTClaimsSet;
 
 import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.AbstractOIDCAuthenticationAction;
 import net.shibboleth.idp.plugin.authn.oidc.rp.OIDCRPException;
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.OpenIDConnectContext;
-import net.shibboleth.oidc.jwt.claims.JWTClaimsValidation;
+import net.shibboleth.oidc.jwt.claims.ClaimsValidator;
 import net.shibboleth.oidc.jwt.claims.JWTValidationException;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
@@ -27,8 +27,8 @@ import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 
 /**
- * Action that validates the claims of the id_token using the supplied 
- * {@link JWTClaimsValidation claims validator}. The verifier <b>must</b> be thread-safe and validate, at
+ * Action that validates the claims of a JWT using the supplied 
+ * {@link ClaimsValidator claims validator}. The verifier <b>must</b> be thread-safe and validate, at
  * minimum the claims set against the OpenID Connect core 1.0 section 3.1.3.7 specification. 
  * 
  * TODO: check these conditions
@@ -72,7 +72,10 @@ public class ValidateTokenClaims extends AbstractOIDCAuthenticationAction {
     @Nullable private JWTClaimsSet claimsSet;
     
     /** The JWT claims validator used to verify the claimsset.*/
-    @NonnullAfterInit private JWTClaimsValidation claimsValidator;
+    @NonnullAfterInit private ClaimsValidator claimsValidator;
+    
+    /** Strategy used to pull out a JWT to validate from the context.*/
+    @NonnullAfterInit private Function<ProfileRequestContext, JWT> jwtLookupStrategy;
     
     /** {@inheritDoc} */
     @Override protected void doInitialize() throws ComponentInitializationException {
@@ -81,6 +84,21 @@ public class ValidateTokenClaims extends AbstractOIDCAuthenticationAction {
         if (claimsValidator ==  null) {
             throw new ComponentInitializationException("JWT ClaimSet Validator cannot be null");
         }
+        if (jwtLookupStrategy ==  null) {
+            throw new ComponentInitializationException("JWT lookup strategy cannot be null");
+        }
+    }
+    
+    /**
+     * Set the lookup strategy that locates the JWT to validate from the context.
+     * 
+     * @param strategy the strategy
+     */
+    public void setJwtLookupStrategy(@Nonnull final Function<ProfileRequestContext, JWT> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+        
+        jwtLookupStrategy = Constraint.isNotNull(strategy," JWT lookup strategy can not be null");
     }
 
     /**
@@ -102,7 +120,7 @@ public class ValidateTokenClaims extends AbstractOIDCAuthenticationAction {
      * @param validator the claims validator.
      */
     public void setClaimsValidator(
-            @Nonnull final JWTClaimsValidation validator) {
+            @Nonnull final ClaimsValidator validator) {
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
         ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
         
@@ -112,12 +130,11 @@ public class ValidateTokenClaims extends AbstractOIDCAuthenticationAction {
     /** {@inheritDoc} */
     @Override
     protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
-            @Nonnull final AuthenticationContext authenticationContext,
-            @Nonnull final OpenIDConnectContext oidcContext) {
+            @Nonnull final AuthenticationContext authenticationContext) {
 
-        final JWT token = oidcContext.getIDToken();
+        final JWT token = jwtLookupStrategy.apply(profileRequestContext);
         if (token == null) {
-            log.error("{} id_token token is not available", getLogPrefix());
+            log.error("{} id_token was not located, nothing to validate", getLogPrefix());
             ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_AUTHN_CTX);
             return false;
         }
@@ -138,10 +155,10 @@ public class ValidateTokenClaims extends AbstractOIDCAuthenticationAction {
     /** {@inheritDoc} */
     @Override
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
-            @Nonnull final AuthenticationContext authenticationContext,
-            @Nonnull final OpenIDConnectContext oidcContext) {
+            @Nonnull final AuthenticationContext authenticationContext) {
 
-        log.debug("{} Validating token claims for subject '{}'",getLogPrefix(),claimsSet.getSubject());
+        log.debug("{} Validating token claims for subject '{}'",getLogPrefix(),
+                claimsSet.getSubject() != null ? claimsSet.getSubject() : "unknown subject");
          
         try {
             claimsValidator.validate(claimsSet,profileRequestContext);
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/DefaultClientIDForIssuerLookupFunction.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/DefaultClientIDForIssuerLookupFunction.java
index 7ff6061..b381298 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/DefaultClientIDForIssuerLookupFunction.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/DefaultClientIDForIssuerLookupFunction.java
@@ -13,7 +13,7 @@ import org.opensaml.messaging.context.navigate.ContextDataLookupFunction;
 import com.nimbusds.oauth2.sdk.id.ClientID;
 import com.nimbusds.oauth2.sdk.id.Issuer;
 
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCProviderMetadataContext;
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
 import net.shibboleth.utilities.java.support.annotation.ParameterName;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCClientMetadataLookupHandler.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCClientMetadataLookupHandler.java
index fcbccc7..f0ac8a9 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCClientMetadataLookupHandler.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCClientMetadataLookupHandler.java
@@ -30,8 +30,8 @@ import org.slf4j.LoggerFactory;
 import com.nimbusds.oauth2.sdk.id.Issuer;
 import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
 
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
 import net.shibboleth.oidc.metadata.ClientInformationResolver;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
 import net.shibboleth.oidc.metadata.criterion.IssuerIDCriterion;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
@@ -42,7 +42,7 @@ import net.shibboleth.utilities.java.support.resolver.ResolverException;
 
 /**
  * Handler for inbound OIDC protocol messages that attempts to locate OIDC metadata for a RP, and attaches it with a
- * {@link OIDCClientMetadataContext} as a child of a pre-existing instance of {@link MessageContext}.
+ * {@link OIDCMetadataContext} as a child of a pre-existing instance of {@link MessageContext}.
  */
 public class OIDCClientMetadataLookupHandler extends AbstractMessageHandler {
 
@@ -116,13 +116,13 @@ public class OIDCClientMetadataLookupHandler extends AbstractMessageHandler {
                 return;
             }
             log.debug("{} Resolved client information for client '{}'", getLogPrefix(), clientInformation.getID());
-            final OIDCClientMetadataContext oidcCtx = new OIDCClientMetadataContext();
+            final OIDCMetadataContext oidcCtx = new OIDCMetadataContext();
             oidcCtx.setClientInformation(clientInformation);
             messageContext.addSubcontext(oidcCtx);
             // Based on that info we know 1) client is valid 2) we know valid
             // redirect uris
             log.debug("{} {} added to MessageContext as child of {}", getLogPrefix(),
-                    OIDCClientMetadataContext.class.getName(), messageContext.getClass().getName());
+                    OIDCMetadataContext.class.getName(), messageContext.getClass().getName());
         } catch (final ResolverException e) {
             log.error("{} ResolverException thrown during client information lookup", getLogPrefix(), e);
         }
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCProviderMetadataLookupHandler.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCProviderMetadataLookupHandler.java
index bee1189..4939173 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCProviderMetadataLookupHandler.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCProviderMetadataLookupHandler.java
@@ -16,10 +16,9 @@ import com.nimbusds.oauth2.sdk.id.Issuer;
 import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
 
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCProviderMetadataContext;
-import net.shibboleth.idp.profile.context.RelyingPartyContext;
 import net.shibboleth.oidc.metadata.ProviderMetadataResolver;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
 import net.shibboleth.oidc.metadata.criterion.IssuerIDCriterion;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
@@ -31,7 +30,7 @@ import net.shibboleth.utilities.java.support.resolver.ResolverException;
 
 /**
  * Handler for inbound OIDC protocol messages that attempts to locate OIDC metadata for a OP (issuer), and attaches it with a
- * {@link OIDCClientMetadataContext} as a child of a pre-existing instance of {@link MessageContext}.
+ * {@link OIDCMetadataContext} as a child of a pre-existing instance of {@link MessageContext}.
  */
 //TODO This might need a way to set which base class to add the metadata too.
 public class OIDCProviderMetadataLookupHandler extends AbstractMessageHandler {
@@ -126,7 +125,9 @@ public class OIDCProviderMetadataLookupHandler extends AbstractMessageHandler {
                 return;
             }
             log.debug("{} Found provider metadata for '{}'", getLogPrefix(), issuerId);
-            entityCtx.addSubcontext(new OIDCProviderMetadataContext(issuerMetadata));
+            final OIDCProviderMetadataContext context = new OIDCProviderMetadataContext();
+            context.setProviderInformation(issuerMetadata);            
+            entityCtx.addSubcontext(context);
         } catch (final ResolverException e) {
             log.error("{} ResolverException thrown during provider metadata lookup", getLogPrefix(), e);
         }
diff --git a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml
index 11a5944..e78d544 100644
--- a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml
+++ b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml
@@ -200,8 +200,8 @@
         
     <!-- CODE flow beans -->
     
-    <bean id="ExchangeCodeForToken" scope="prototype"
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ExchangeCodeForToken" 
+    <bean id="ExchangeCodeForAccessToken" scope="prototype"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ExchangeCodeForAccessToken" 
         p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
         p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
         p:httpClient="#{getObject('shibboleth.authn.oidc.rp.HttpClient') ?: getObject('shibboleth.InternalHttpClient')}"
@@ -209,6 +209,11 @@
         p:tokenResponseDecoderStrategy="#{getObject('shibboleth.authn.oidc.rp.TokenResponseDecoder') ?: getObject('shibboleth.authn.oidc.rp.DefaultTokenResponseDecoder')}"
         p:tokenRequestEncoderStrategy="#{getObject('shibboleth.authn.oidc.rp.TokenRequestEncoder') ?: getObject('shibboleth.authn.oidc.rp.DefaultTokenRequestEncoder')}"/>   
         
+     <bean id="ValidateOAuthAccessTokenResponse" 
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateOAuthAccessTokenResponse"
+        p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
+        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"/>
+     
      <bean id="ExtractIDTokenFromTokenResponse" scope="prototype"
         class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ExtractIDTokenFromResponse"
         p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
@@ -252,6 +257,129 @@
     
     <!-- Process token -->
     
+    <!-- <bean id="PopulateTokenSignatureSigningParameters"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.PopulateOIDCSignatureSigningParameters " scope="prototype"
+        p:configurationLookupStrategy-ref="shibboleth.SignatureSigningConfigurationLookup"
+        p:signatureSigningParametersResolver-ref="shibboleth.oidc.TokenSignatureSigningParametersResolver">
+        <property name="securityParametersContextLookupStrategy">
+            <bean parent="shibboleth.Functions.Compose"
+                c:g-ref="shibboleth.ChildLookupOrCreate.SecurityParameters"
+                c:f-ref="shibboleth.ChildLookup.RelyingParty" />
+        </property>
+        <property name="existingParametersContextLookupStrategy">
+            <bean parent="shibboleth.Functions.Compose"
+                c:g-ref="shibboleth.ChildLookup.SecurityParameters"
+                c:f-ref="shibboleth.MessageContextLookup.Outbound" />
+        </property>
+    </bean> -->
+    
+    <!-- Default id_token JWT validation wiring. -->
+    
+    <bean id="ValidateIDTokenClaims" scope="prototype"
+       class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateTokenClaims"
+       p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
+       p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
+       p:cleanupHook="#{getObject('shibboleth.authn.oidc.rp.jwt.claims.CleanUpHook') 
+           ?: getObject('shibboleth.authn.oidc.rp.jwt.claims.DefaultCleanupHook')}"
+       p:claimsValidator="#{getObject('shibboleth.authn.oidc.rp.IDTokenClaimsValidator') 
+           ?: getObject('DefaultIDTokenClaimsValidator')}"
+        p:jwtLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.IDTokenLookupStrategy') 
+           ?: getObject('DefaultIDTokenLookupStrategy')}"/>
+        
+    <bean id="DefaultIDTokenLookupStrategy" 
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.DefaultIDTokenLookupStrategy"/>
+
+    <bean id="DefaultIDTokenClaimsValidator"
+        class="net.shibboleth.oidc.security.jwt.claims.impl.ChainingJWTClaimsValidator"
+        p:claimValidators-ref="ClaimsValidators" />
+        
+    <bean id="OIDCProviderMetadataContextChildLookup"
+        class="org.opensaml.messaging.context.navigate.ChildContextLookup"
+        c:type="#{ T(net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext) }" />
+
+    <bean id="ExpiryClaimsValidator"
+        class="net.shibboleth.oidc.security.jwt.claims.impl.ExpiryClaimsValidator"
+        p:clockSkew="%{idp.policy.clockSkew:PT1M}" />
+
+    <bean id="NotBeforeClaimsValidator"
+        class="net.shibboleth.oidc.security.jwt.claims.impl.NotBeforeClaimsValidator"
+        p:clockSkew="%{idp.policy.clockSkew:PT1M}" />
+        
+    <bean id="IssuedAtClaimsValidator"
+        class="net.shibboleth.oidc.security.jwt.claims.impl.IssuedAtClaimsValidator"
+        p:clockSkew="%{idp.policy.clockSkew:PT1M}"
+        p:messageLifetime="%{idp.policy.messageLifetime:PT1M}"
+        p:requiredRule="false" />
+
+    <bean id="IssuerClaimsValidator"
+        class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
+        p:claimName="iss" p:valueToMatchLookupStrategy-ref="IssuerIDFromOIDCProviderMetadataContextLookupFunction" />
+    
+    <!-- check AZP is required if more than one audience value -->    
+    <bean id="AzpClaimRequiredValidator" 
+         class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator">
+         <property name="activationCondition">
+            <bean id="MultipleValuesExist" 
+                class="net.shibboleth.oidc.security.jwt.claims.impl.NumberOfClaimValuesActivationCondition"
+                c:claimToCheck="aud"
+                c:numberOfValuesPredicate-ref="ManyValuesPredicate"/>
+         </property>
+         <property name="requiredClaims">
+            <list>
+                <value>azp</value>
+            </list>
+         </property>
+    </bean>
+    
+    <!-- TODO, seems like this could be done in XML somehow -->
+    <bean id="ManyValuesPredicate" 
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ManyValuesIntegerComparisonPredicate" />
+        
+    <bean id="AzpClaimsValidator"
+        class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
+        p:claimName="azp" p:valueToMatchLookupStrategy-ref="ClientIDFromOIDCMetadataContextLookupFunction"> 
+         <property name="activationCondition">
+            <bean id="AzpClaimExistsCondition"
+                class="net.shibboleth.oidc.security.jwt.claims.impl.ClaimExistsActivationCondition"
+                c:claimToCheck="azp"/>
+        </property>
+    </bean>
+        
+    <bean id="IssuerIDFromOIDCProviderMetadataContextLookupFunction"
+        class="net.shibboleth.oidc.profile.logic.IssuerIDFromOIDCProviderMetadataContextLookupFunction"
+        p:oIDCMetadataContextLookupStrategy-ref="OIDCProviderMetadataContextFromOutboundPeerLookupStrategy"/>
+        
+    <!-- TODO This bean could be replaced by XML functions? -->
+    <bean id="OIDCProviderMetadataContextFromOutboundPeerLookupStrategy"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.OIDCProviderMetadataFromOuboundPeerLookupStrategy"/>
+
+    <bean id="AudienceClaimsValidator"
+        class="net.shibboleth.oidc.security.jwt.claims.impl.AudienceClaimsValidator"
+        p:audienceLookupStrategy-ref="ClientIDFromOIDCMetadataContextLookupFunction"/>
+    
+    <bean id="ClientIDFromOIDCMetadataContextLookupFunction"
+        class="net.shibboleth.oidc.profile.logic.ClientIDFromOIDCMetadataContextLookupFunction">
+        <property name="oIDCMetadataContextLookupStrategy">
+            <bean parent="shibboleth.Functions.Compose"
+                c:g-ref="OIDCMetadataContextChildLookup"
+                c:f-ref="shibboleth.MessageContextLookup.Outbound" />
+        </property>
+    </bean>
+    
+    <bean id="OIDCMetadataContextChildLookup"
+        class="org.opensaml.messaging.context.navigate.ChildContextLookup"
+        c:type="#{ T(net.shibboleth.oidc.metadata.context.OIDCMetadataContext) }" />
+    
+    <util:list id="ClaimsValidators" value-type="net.shibboleth.oidc.jwt.claims.ClaimsValidator">
+        <ref bean="ExpiryClaimsValidator" />
+        <ref bean="NotBeforeClaimsValidator" />
+        <ref bean="AzpClaimRequiredValidator"/>
+        <ref bean="AzpClaimsValidator"/>
+        <ref bean="IssuedAtClaimsValidator" /> 
+        <ref bean="IssuerClaimsValidator" /> <!-- TODO prevent: if it contains additional audiences not trusted by the Client. -->
+        <ref bean="AudienceClaimsValidator" />
+    </util:list> 
+    
    
     
     <!-- OLD STUFF -->
@@ -270,81 +398,13 @@
     <!-- Populate RP UI info from metadata? -->
     <util:constant id="shibboleth.authn.oidc.rp.populateUIInfo" static-field="java.lang.Boolean.FALSE" />
 
-   <!--  <bean id="SetOIDCInformation" class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.SetOIDCInformation"
-        p:redirectURI="%{idp.oidc.rp.redirectURI:}"
-        p:clientID="%{idp.oidc.rp.clientID:null}"
-        p:clientSecret="%{idp.oidc.rp.clientSecret:null}"
-        p:providerMetadataLocation="%{idp.oidc.rp.providerConfigurationDocument:null}"
-        p:scope="%{idp.oidc.rp.scope:null}">
-            
-        <property name="responseType" value="id_token token"/>
-    </bean> -->
-
     <bean id="ValidateIDTokenSignature"
         class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateIDTokenSignature" />
 
-    <bean id="ValidateOIDCAuthentication" class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateOIDCAuthentication" scope="prototype" />
+    <bean id="ValidateOIDCAuthentication" 
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateOIDCAuthentication" scope="prototype" />
+
 
-        
-    <bean id="ValidateTokenClaims" scope="prototype"
-	   class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateTokenClaims"
-	   p:cleanupHook="#{getObject('shibboleth.authn.oidc.rp.jwt.claims.CleanUpHook') 
-	       ?: getObject('shibboleth.authn.oidc.rp.jwt.claims.DefaultCleanupHook')}"
-	   p:claimsValidator="#{getObject('shibboleth.authn.oidc.rp.RPTokenClaimsVerifier') 
-           ?: getObject('shibboleth.authn.oidc.rp.DefaultRPTokenClaimsVerifier')}" />
-    
-    <!-- TODO ensure these claims are correct in the general OIDC case. -->
-     <!-- OIDC claims verification Other claim verifications e.g. ACR and AZP-->
-    <bean id="shibboleth.authn.oidc.rp.DefaultRPTokenClaimsVerifier"
-        class="net.shibboleth.oidc.security.jwt.claims.impl.ChainingJWTClaimsValidator">
-        <property name="claimValidators">
-            <list>
-            <bean id="requiredClaimsValidator" 
-                class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator"
-                p:requiredClaims="#{getObject('shibboleth.authn.oidc.rp.RequiredOIDCClaims') ?: 
-                                getObject('shibboleth.authn.oidc.rp.DefaultRequiredOIDCClaims')}"/>
-            <bean id="issuerClaimValidator" 
-                class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
-                p:claimName="#{T(net.shibboleth.oidc.security.jwt.claims.impl.JWTClaims).ISSUER_CLAIM.claimName}"
-                p:valueToMatchLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.jwt.IssuerLookupStrategy') ?: 
-                                getObject('shibboleth.authn.oidc.rp.jwt.DefaultIssuerLookupStrategy')}"/>              
-            <bean id="audienceClaimValidator" 
-                class="net.shibboleth.oidc.security.jwt.claims.impl.AudienceClaimsValidator"
-                p:audienceLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.jwt.AudienceLookupStrategy') ?: 
-                                getObject('shibboleth.authn.oidc.rp.jwt.DefaultAudienceLookupStrategy')}"/>
-            <bean id="notBeforeClaimValidator" 
-                class="net.shibboleth.oidc.security.jwt.claims.impl.NotBeforeClaimsValidator"
-                p:clockSkew="%{idp.duo.oidc.jwt.verifier.clockSkew:PT60S}"/>
-            <bean id="expiryClaimValidator" 
-                class="net.shibboleth.oidc.security.jwt.claims.impl.ExpiryClaimsValidator"
-                p:clockSkew="%{idp.duo.oidc.jwt.verifier.clockSkew:PT60S}"/>
-             <bean id="issuedAtClaimValidator" 
-                class="net.shibboleth.oidc.security.jwt.claims.impl.IssuedAtClaimsValidator"
-                p:clockSkew="%{idp.duo.oidc.jwt.verifier.clockSkew:PT60S}"
-                p:messageLifetime="%{idp.duo.oidc.jwt.verifier.messageLifetime:PT60S}"/>
-            
-             <bean id="authenticationTimeClaimValidator" 
-                class="net.shibboleth.oidc.security.jwt.claims.impl.AuthenticationTimeClaimsValidator"
-                p:authnLifetime="%{idp.duo.oidc.jwt.verifier.authLifetime:PT60S}"
-                p:clockSkew="%{idp.duo.oidc.jwt.verifier.clockSkew:PT60S}"
-                p:activationCondition="#{getObject('shibboleth.authn.oidc.rp.jwt.AuthTimeActivationCondition') ?: 
-                                getObject('shibboleth.authn.oidc.rp.jwt.DefaultAuthTimeActivationCondition')}"
-                p:requested="#{getObject('shibboleth.authn.oidc.rp.jwt.AuthTimeRequested') ?: 
-                                getObject('shibboleth.authn.oidc.rp.jwt.DefaultAuthTimeRequested')}"/>
-             <!-- <bean id="nonceClaimValidator" 
-                class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
-                p:claimName="nonce"
-                p:valueToMatchLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.jwt.NonceLookupStrategy') ?: 
-                                getObject('shibboleth.authn.oidc.rp.jwt.DefaultNonceLookupStrategy')}"
-                p:activationCondition="#{getObject('shibboleth.authn.oidc.rp.jwt.NonceActivationCondition') ?: 
-                                getObject('shibboleth.authn.oidc.rp.jwt.DefaultNonceActivationCondition')}"/> -->
-             <bean id="functionClaimValidator"
-                class="net.shibboleth.oidc.security.jwt.claims.impl.FunctionClaimsValidator"
-                p:validator="#{getObject('shibboleth.authn.oidc.rp.ExtendedClaimsValidator')}"/>
-            </list>
-        </property>    
-    </bean> 
-    
     <bean id="shibboleth.authn.oidc.rp.jwt.DefaultAuthTimeActivationCondition"
         class="net.shibboleth.oidc.security.jwt.claims.impl.ForcedAuthenticationActivationCondition"/>
 
diff --git a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-flow.xml b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-flow.xml
index ebcf8e6..443ed3b 100644
--- a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-flow.xml
+++ b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-flow.xml
@@ -62,12 +62,12 @@
         <evaluate expression="ValidateAuthenticationResponseResult"/>
         <evaluate expression="ValidateResponseStateMatchesRequest"/>
         <evaluate expression="'proceed'" />
-        <transition on="proceed" to="SwitchOnOIDCFlow" />
+        <transition on="proceed" to="SwitchOnGrantType" />
     </action-state>
     
-    <!-- Switch flow path based on OIDC response_type/flow used. 
-    TODO possible places for an NPE?-->
-    <decision-state id="SwitchOnOIDCFlow">
+    <!-- Switch flow path based on OIDC grant_type used. 
+    TODO possible places for an NPE, use strategy?-->
+    <decision-state id="SwitchOnGrantType">
         <!-- check a null response_type first, should never get here -->
         <if test="opensamlProfileRequestContext.getSubcontext('net.shibboleth.idp.authn.context.AuthenticationContext')
                             .getSubcontext('org.opensaml.profile.context.ProfileRequestContext').getOutboundMessageContext().getSubcontext('net.shibboleth.idp.plugin.authn.oidc.rp.context.ResponseTypeAndModeContext').getResponseType() == null"
@@ -88,7 +88,8 @@
     </decision-state>
 
     <action-state id="CodeFlow">
-        <evaluate expression="ExchangeCodeForToken"/> 
+        <evaluate expression="ExchangeCodeForAccessToken"/> 
+        <evaluate expression="ValidateOAuthAccessTokenResponse"/>
         <evaluate expression="ExtractIDTokenFromTokenResponse"/>       
         <evaluate expression="'proceed'" />
         
@@ -110,12 +111,14 @@
      <action-state id="UnsupportedFlow">
 
         <evaluate expression="'proceed'" />
-        <transition on="proceed" to="ValidateToken" />
+        <transition on="proceed" to="END" />
     </action-state>
     
+    <!-- TODO claim validation will differ per grant_type -->
     <action-state id="ValidateToken">
-        
-    
+         <!-- <evaluate expression="PopulateTokenSignatureSigningParameters" /> -->
+        <!--  <evaluate expression="PopulateTokenEncryptionParameters" /> -->
+         <evaluate expression="ValidateIDTokenClaims" />
          <transition on="proceed" to="SetPrincipal" />
     </action-state>
 
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/decoding/impl/DefaultTokenResponseDecoderTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/decoding/impl/DefaultTokenResponseDecoderTest.java
index 57d01e1..b006417 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/decoding/impl/DefaultTokenResponseDecoderTest.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/decoding/impl/DefaultTokenResponseDecoderTest.java
@@ -60,7 +60,7 @@ public class DefaultTokenResponseDecoderTest extends AbstractOIDCTest {
         when(mockStatusLine.getStatusCode()).thenReturn(200);
         when(response.getStatusLine()).thenReturn(mockStatusLine);
         when(response.getEntity()).thenReturn(mockHttpEntity);
-        when(mockHttpEntity.getContent()).thenReturn(new ByteArrayInputStream(ID_TOKEN_RESPONSE.getBytes()));
+        when(mockHttpEntity.getContent()).thenReturn(new ByteArrayInputStream(ACCESS_TOKEN_RESPONSE.getBytes()));
         final Map<String, Object> decodedResponse = decoder.apply(response);
         assertNotNull(decodedResponse);
         assertNotNull(decodedResponse.get("id_token"));
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCTest.java
index 0c183e7..efe5b44 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCTest.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCTest.java
@@ -36,10 +36,10 @@ import net.minidev.json.JSONObject;
 import net.minidev.json.parser.JSONParser;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCProviderMetadataContext;
 import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
 import net.shibboleth.idp.profile.testing.RequestContextBuilder;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
 import net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 
@@ -84,9 +84,9 @@ public abstract class AbstractOIDCTest {
             + "\"A192GCMKW\",\"A256GCMKW\",\"dir\"],\"userinfo_encryption_enc_values_supported\":[\"A128CBC-HS256\","
             + "\"A192CBC-HS384\",\"A256CBC-HS512\",\"A128GCM\",\"A192GCM\",\"A256GCM\"]}";
     
-    /** Real response from openid connect tests,*/
+    /** Real response from openid connect tests.*/
     @Nonnull @NotEmpty
-    protected final String ID_TOKEN_RESPONSE = "{\n"
+    protected final String ACCESS_TOKEN_RESPONSE = "{\n"
             + "  \"access_token\": \"W0y5aDNAzEPNpSzu1cuMG904BZuQFZJUUwG5F3ct0zydZWy1ji\",\n"
             + "  \"token_type\": \"Bearer\",\n"
             + "  \"id_token\": \"eyJraWQiOiJiNjliYzcyOS05NDJjLTQzNjItYmM2YS03OWU3MjAwOWY0Yzg"
@@ -151,14 +151,14 @@ public abstract class AbstractOIDCTest {
         prc.setOutboundMessageContext(outMsgCtx);      
 
         final JSONParser parser = new JSONParser(JSONParser.MODE_JSON_SIMPLE);
-        final OIDCClientMetadataContext metadataContext = new OIDCClientMetadataContext();
+        final OIDCMetadataContext metadataContext = new OIDCMetadataContext();
         metadataContext.setClientInformation(
                 OIDCClientInformation.parse((JSONObject)((JSONArray)parser.parse(CLIENT_METADATA)).get(0)));
         outMsgCtx.addSubcontext(metadataContext);
         
         final OIDCPeerEntityContext peerEntitCtx = outMsgCtx.getSubcontext(OIDCPeerEntityContext.class,true);
-        final OIDCProviderMetadataContext providerCtx = 
-                new OIDCProviderMetadataContext(
+        final OIDCProviderMetadataContext providerCtx = new OIDCProviderMetadataContext();
+        providerCtx.setProviderInformation(
                         OIDCProviderMetadata.parse((JSONObject)parser.parse(GOOD_PROVIDER_CONFIGURATION_INFO)));
         peerEntitCtx.addSubcontext(providerCtx);
         outMsgCtx.addSubcontext(peerEntitCtx);
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForTokenTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForTokenTest.java
index 21c54ed..c2dccf9 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForTokenTest.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExchangeCodeForTokenTest.java
@@ -54,12 +54,12 @@ import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
 
 /**
- * Tests for the {@link ExchangeCodeForToken} action.
+ * Tests for the {@link ExchangeCodeForAccessToken} action.
  */
 public class ExchangeCodeForTokenTest extends AbstractOIDCTest {
     
     /** The action to test.*/
-    @Nonnull private ExchangeCodeForToken exchangeAction;
+    @Nonnull private ExchangeCodeForAccessToken exchangeAction;
     
     
     @BeforeMethod
@@ -67,7 +67,7 @@ public class ExchangeCodeForTokenTest extends AbstractOIDCTest {
         
         super.setup();
         
-        exchangeAction = new ExchangeCodeForToken();
+        exchangeAction = new ExchangeCodeForAccessToken();
         exchangeAction.setAuthenticationContextLookupStrategy(new ParentContextLookup<>(AuthenticationContext.class));
         exchangeAction.setProfileContextLookupStrategy(new ChildContextLookup<>(ProfileRequestContext.class).compose(
                 new ChildContextLookup<>(AuthenticationContext.class)
@@ -91,7 +91,7 @@ public class ExchangeCodeForTokenTest extends AbstractOIDCTest {
         Mockito.when(httpResponse.getStatusLine()).thenReturn(statusLine);
 
         Mockito.when(statusLine.getStatusCode()).thenReturn(200);
-        Mockito.when(httpResponse.getEntity()).thenReturn(new StringEntity(ID_TOKEN_RESPONSE));
+        Mockito.when(httpResponse.getEntity()).thenReturn(new StringEntity(ACCESS_TOKEN_RESPONSE));
         Mockito.when(httpClient.execute((HttpUriRequest) Mockito.any(), (HttpContext) Mockito.any()))
                 .thenReturn(httpResponse);
 
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExtractIDTokenFromResponseTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExtractIDTokenFromResponseTest.java
new file mode 100644
index 0000000..3f16ce5
--- /dev/null
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ExtractIDTokenFromResponseTest.java
@@ -0,0 +1,71 @@
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import java.io.ByteArrayInputStream;
+import java.util.Map;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.messaging.context.navigate.ParentContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.springframework.webflow.execution.Event;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.nimbusds.jose.shaded.json.parser.JSONParser;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.TokenResponseContext;
+import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+/** Tests for ExtractIDTokenFromResponse.*/
+public class ExtractIDTokenFromResponseTest extends AbstractOIDCTest {
+    
+    private ExtractIDTokenFromResponse action;
+    
+    
+    @BeforeMethod
+    public void setup() throws Exception {
+        super.setup();
+        action = new ExtractIDTokenFromResponse();       
+
+        final TokenResponseContext trc = new TokenResponseContext();
+        prc.getInboundMessageContext().addSubcontext(trc);        
+
+        action.setProfileContextLookupStrategy(new ChildContextLookup<>(ProfileRequestContext.class).compose(
+                new ChildContextLookup<>(AuthenticationContext.class)
+                .compose(new WebflowRequestContextProfileRequestContextLookup())));      
+    }
+    
+    @Test
+    public void testExtractSignedToken_Success() throws ComponentInitializationException {
+        action.setRawIdTokenLookupStrategy(prc -> "eyJraWQiOiJiNjliY"
+                + "zcyOS05NDJjLTQzNjItYmM2YS03OWU3MjAwOWY0YzgiLCJhbG"
+                + "ciOiJSUzI1NiJ9.eyJhdF9oYXNoIjoiM0pBZmFibUx4eWVnNj"
+                + "JJM2JiT0RrdyIsInN1YiI6InVzZXItc3ViamVjdC0xMjM0NTM"
+                + "xIiwiYXVkIjoibXl0ZXN0Y2xpZW50IiwiaXNzIjoiaHR0cHM6X"
+                + "C9cL3d3dy5jZXJ0aWZpY2F0aW9uLm9wZW5pZC5uZXRcL3Rlc3"
+                + "RcL2FcL3Rlc3RfcnBfcHJveHlcLyIsImV4cCI6MTY0MzI3NTQy"
+                + "NCwiaWF0IjoxNjQzMjc1MTI0fQ.igU798iSZYUR7Z6_MQQend"
+                + "FCqm9Pf6Xpd4KtnHcPGG5FxtXPiDhlyhP_7ewSIQtzWxQ5wEat"
+                + "ixDJWl2oRasivNCJyl6ZNeUG4YuT8S7xlgpUumoycBxrmomS7"
+                + "wgZSola8oZo8BuiRKlWzqLLtFkAChGi5iJEtHfVBe3k3PyQAs"
+                + "WRQdtixkvdxvyLqFLznIaPmMH-OZ82w7sJf4bpalZSAaR5NLpy"
+                + "zLFw-r81IOtOVrpQtnycCw0w_JxAP16GyZXCJc56vCEo8rji7"
+                + "juk3szTOclbsYFrrd9iokWHl0qJa0G1ev5XQLsiUxYxgO1Nw-"
+                + "CAnHtESZ9w7JIfLLX1YlY73g");
+        
+        action.initialize();
+        final Event event = action.execute(src);
+        assertNull(event);
+        assertNotNull(prc.getInboundMessageContext().getSubcontext(TokenResponseContext.class).getIdToken());
+        
+    }
+    
+    //TODO need encrypted as well?
+
+}
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java
index 9a7c66a..c78dd11 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java
@@ -21,19 +21,25 @@ import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.io.IOException;
 import java.net.URI;
+import java.time.Instant;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import javax.annotation.Nonnull;
 
+import org.apache.http.HttpResponse;
+import org.apache.http.StatusLine;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.entity.StringEntity;
 import org.apache.http.protocol.HttpContext;
 import org.junit.Test;
+import org.mockito.Mockito;
 import org.opensaml.messaging.context.MessageContext;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
@@ -46,7 +52,14 @@ import org.springframework.webflow.engine.impl.FlowExecutionImpl;
 import org.springframework.webflow.execution.FlowExecution;
 import org.springframework.webflow.test.MockFlowBuilderContext;
 
-import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JOSEObjectType;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.JWSHeader;
+import com.nimbusds.jose.KeyLengthException;
+import com.nimbusds.jose.crypto.MACSigner;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
 import com.nimbusds.oauth2.sdk.ResponseMode;
 import com.nimbusds.oauth2.sdk.ResponseType;
 import com.nimbusds.oauth2.sdk.id.ClientID;
@@ -64,10 +77,10 @@ import net.shibboleth.idp.authn.context.ExternalAuthenticationContext;
 import net.shibboleth.idp.authn.impl.ExternalAuthenticationImpl;
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.ResponseTypeAndModeContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCClientMetadataContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.OIDCProviderMetadataContext;
 import net.shibboleth.idp.plugin.authn.test.flow.AbstractAuthnXmlFlowExecutionTests;
 import net.shibboleth.idp.plugin.authn.test.flow.mock.MockFlowBuilder;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
 import net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
@@ -78,12 +91,12 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
 
     private final String GOOD_PROVIDER_CONFIGURATION_INFO = "{\n"
             + "\"issuer\": \"https://op.example.com\",\n"
-            + "\"authorization_endpoint\": \"https://example.oidc.op.org/o/oauth2/v2/auth\",\n"
-            + "\"device_authorization_endpoint\": \"https://oauth2.googleapis.com/device/code\",\n"
-            + "\"token_endpoint\": \"https://oauth2.googleapis.com/token\",\n"
-            + "\"userinfo_endpoint\": \"https://openidconnect.googleapis.com/v1/userinfo\",\n"
-            + "\"revocation_endpoint\": \"https://oauth2.googleapis.com/revoke\",\n"
-            + "\"jwks_uri\": \"https://www.googleapis.com/oauth2/v3/certs\",\n"
+            + "\"authorization_endpoint\": \"https://op.example.com/o/oauth2/v2/auth\",\n"
+            + "\"device_authorization_endpoint\": \"https://op.example.com/device/code\",\n"
+            + "\"token_endpoint\": \"https://op.example.com/token\",\n"
+            + "\"userinfo_endpoint\": \"https://op.example.com/v1/userinfo\",\n"
+            + "\"revocation_endpoint\": \"https://op.example.com/revoke\",\n"
+            + "\"jwks_uri\": \"https://op.example.com/oauth2/v3/certs\",\n"
             + "\"response_types_supported\": [\n"
             + "\"code\",\n"
             + "\"token\",\n"
@@ -143,12 +156,14 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
             + "      \"https://192.168.0.150/static\"\n"
             + "    ],\n"
             + "    \"client_id\": \"demo_rp\",\n"
+            + "    \"client_secret\": \"demo_rp_secret\",\n"
             + "    \"response_types\": [\n"
             + "      \"id_token\",\n"
             + "      \"id_token token\"\n"
             + "    ]\n"
             + "  }"
             + "]";
+
     
     
     /** Path to the flow to be tested.*/
@@ -203,27 +218,85 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
         addBeanDefinition(builderContext, "shibboleth.IdentifiableBeanPostProcessor",BeanDefinitionBuilder.
                 genericBeanDefinition(IdentifiableBeanPostProcessor.class).getBeanDefinition());
         
-
-        //create Mock HttpClient
-        final HttpClient httpClient = mock(HttpClient.class);
-        addBeanSingleton(builderContext, "shibboleth.InternalHttpClient", httpClient);
+        addBeanDefinition(builderContext, "shibboleth.ReplayCache",BeanDefinitionBuilder.
+                genericBeanDefinition(org.opensaml.storage.ReplayCache.class).getBeanDefinition());
+        
         
         try {
+            //create Mock HttpClient
+            /*
+             * This is brittle and only works because the HttpGet request for the metadata
+             * is different than that for the type of request to the token endpoint. If
+             * more endpoints are needed, this should be done properly.
+             */
+            final HttpClient httpClient = mock(HttpClient.class);
+            
+            final HttpResponse httpResponse = Mockito.mock(HttpResponse.class);
+            final StatusLine statusLine = Mockito.mock(StatusLine.class);
+            when(httpResponse.getStatusLine()).thenReturn(statusLine);
+            when(statusLine.getStatusCode()).thenReturn(200);
+
             when(httpClient.
-                    execute(any(HttpUriRequest.class),any(ResponseHandler.class),any(HttpContext.class)))
+                    execute(any(HttpGet.class),any(ResponseHandler.class),any(HttpContext.class)))
                     .thenReturn(OIDCProviderMetadata.parse(GOOD_PROVIDER_CONFIGURATION_INFO));
-        } catch (ParseException | IOException e) {
+            
+            
+            
+            Mockito.when(httpResponse.getEntity()).thenReturn(new StringEntity(createAccessTokenResponseJSON()));
+            Mockito.when(httpClient.execute((HttpUriRequest) Mockito.any(), (HttpContext) Mockito.any()))
+            .thenReturn(httpResponse);
+            
+            addBeanSingleton(builderContext, "shibboleth.InternalHttpClient", httpClient);
+            
+           
+        } catch (final Exception e) {
             log.error("Could not mock HTTP response",e);
         }
 
         
-        loadBeanDefinitionsFromXmlFile(builderContext, new ClassPathResource("META-INF/net.shibboleth.idp/postconfig.xml"));
+        loadBeanDefinitionsFromXmlFile(builderContext, 
+                new ClassPathResource("META-INF/net.shibboleth.idp/postconfig.xml"));
         
-        loadBeanDefinitionsFromXmlFile(builderContext, new ClassPathResource("conf/test-relyingparty-resolver-service.xml"));
+        loadBeanDefinitionsFromXmlFile(builderContext, 
+                new ClassPathResource("conf/test-relyingparty-resolver-service.xml"));
         
         loadBeanDefinitionsFromXmlFile(builderContext, new ClassPathResource("conf/additional-system-beans.xml"));
     }
     
+    /**
+     * Create an OAuth access token with a runtime constructed id_token. This allows the
+     * expiry to be current.
+     * 
+     * TODO the JWT is signed with a local MAC and is not consistent with the OP metadata. Might need to change this
+     * 
+     * @return a serialized access token response.
+     * 
+     * @throws KeyLengthException on error
+     * @throws JOSEException on error
+     */
+    private String createAccessTokenResponseJSON() throws KeyLengthException, JOSEException {
+        final var header = new JWSHeader.Builder(JWSAlgorithm.HS256)
+                .type(JOSEObjectType.JWT)
+                .build();
+        final var payload = new JWTClaimsSet.Builder()
+                .issuer("https://op.example.com")
+                .audience(List.of("demo_rp","demo_rp2"))
+                .subject("jdoe")
+                .claim("azp", "demo_rp")
+                .expirationTime(Date.from(Instant.now().plusSeconds(120)))
+                .build();
+        final var signedJWT = new SignedJWT(header,payload);
+        signedJWT.sign(new MACSigner("Xp2s5v8y/B?E(H+MbQeThWmYq3t6w9z$"));
+        final String accessTokenSerialized = "{\n"
+        + "  \"access_token\": \"W0y5aDNAzEPNpSzu1cuMG904BZuQFZJUUwG5F3ct0zydZWy1ji\",\n"
+        + "  \"token_type\": \"Bearer\",\n"
+        + "  \"id_token\": \""+signedJWT.serialize()+"\",\n"
+        + "  \"scope\": \"openid\"\n"
+        + "}";
+        log.debug("Access token: \n {}",accessTokenSerialized);
+        return accessTokenSerialized;
+    }
+    
     
     @Override
     @Nonnull protected ProfileRequestContext buildProfileRequestContext(@Nonnull final String flowId,
@@ -301,7 +374,8 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
         
         final OIDCPeerEntityContext peerCtx = new OIDCPeerEntityContext();
         OIDCProviderMetadata providerMetadata = OIDCProviderMetadata.parse(GOOD_PROVIDER_CONFIGURATION_INFO);
-        final OIDCProviderMetadataContext providerMetadataCtx = new OIDCProviderMetadataContext(providerMetadata);
+        final OIDCProviderMetadataContext providerMetadataCtx = new OIDCProviderMetadataContext();
+        providerMetadataCtx.setProviderInformation(providerMetadata);
         peerCtx.addSubcontext(providerMetadataCtx);
         
         outMsgCtx.addSubcontext(peerCtx);
@@ -313,7 +387,7 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
         nestPrc.getOutboundMessageContext().addSubcontext(respCtx);
         
         final JSONParser parser = new JSONParser(JSONParser.MODE_JSON_SIMPLE);
-        final OIDCClientMetadataContext metadataContext = new OIDCClientMetadataContext();
+        final OIDCMetadataContext metadataContext = new OIDCMetadataContext();
         metadataContext.setClientInformation(
                 OIDCClientInformation.parse((JSONObject)((JSONArray)parser.parse(CLIENT_METADATA)).get(0)));
         nestPrc.getOutboundMessageContext().addSubcontext(metadataContext);
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TokenResponseIDTokenLookupStrategyTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TokenResponseIDTokenLookupStrategyTest.java
new file mode 100644
index 0000000..fcfd3bb
--- /dev/null
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TokenResponseIDTokenLookupStrategyTest.java
@@ -0,0 +1,74 @@
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import java.io.ByteArrayInputStream;
+import java.util.Map;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.TokenResponseContext;
+
+/** Tests for TokenResponseIDTokenLookupStrategy.*/
+public class TokenResponseIDTokenLookupStrategyTest extends AbstractOIDCTest {
+    
+    /** The strategy to test.*/
+    private TokenResponseIDTokenLookupStrategy strategy;
+    
+    
+    @BeforeMethod
+    public void setup() throws Exception {
+        super.setup();
+        strategy = new TokenResponseIDTokenLookupStrategy();
+        ObjectMapper mapper = new ObjectMapper();
+        
+        final Map<String, Object> rawResponse = mapper.readValue(
+                new ByteArrayInputStream(ACCESS_TOKEN_RESPONSE.getBytes()), new TypeReference<Map<String, Object>>() {});
+        final TokenResponseContext trc = new TokenResponseContext();
+        trc.setRawTokenResponse(rawResponse);
+        prc.getInboundMessageContext().addSubcontext(trc);
+        
+    }
+    
+    @Test
+    public void testLookup_Success() {
+        final String rawToken = strategy.apply(prc);
+        assertNotNull(rawToken);
+        assertEquals(rawToken, "eyJraWQiOiJiNjliYzcyOS05NDJjLTQzNjItYmM2YS0"
+                + "3OWU3MjAwOWY0YzgiLCJhbGciOiJSUzI1NiJ9.eyJhdF9oYXNoIjoiM"
+                + "0pBZmFibUx4eWVnNjJJM2JiT0RrdyIsInN1YiI6InVzZXItc3ViamVj"
+                + "dC0xMjM0NTMxIiwiYXVkIjoibXl0ZXN0Y2xpZW50IiwiaXNzIjoiaHR0"
+                + "cHM6XC9cL3d3dy5jZXJ0aWZpY2F0aW9uLm9wZW5pZC5uZXRcL3Rlc3Rc"
+                + "L2FcL3Rlc3RfcnBfcHJveHlcLyIsImV4cCI6MTY0MzI3NTQyNCwiaWF0"
+                + "IjoxNjQzMjc1MTI0fQ.igU798iSZYUR7Z6_MQQendFCqm9Pf6Xpd4Ktn"
+                + "HcPGG5FxtXPiDhlyhP_7ewSIQtzWxQ5wEatixDJWl2oRasivNCJyl6ZN"
+                + "eUG4YuT8S7xlgpUumoycBxrmomS7wgZSola8oZo8BuiRKlWzqLLtFkAC"
+                + "hGi5iJEtHfVBe3k3PyQAsWRQdtixkvdxvyLqFLznIaPmMH-OZ82w7sJf"
+                + "4bpalZSAaR5NLpyzLFw-r81IOtOVrpQtnycCw0w_JxAP16GyZXCJc56v"
+                + "CEo8rji7juk3szTOclbsYFrrd9iokWHl0qJa0G1ev5XQLsiUxYxgO1Nw"
+                + "-CAnHtESZ9w7JIfLLX1YlY73g");
+    }
+    
+    @Test
+    public void testLookup_NoResponseContext() {
+        prc.getInboundMessageContext().removeSubcontext(TokenResponseContext.class);
+        final String rawToken = strategy.apply(prc);
+        assertNull(rawToken);
+       
+    }
+    
+    @Test
+    public void testLookup_NoInboundContext() {
+        prc.setInboundMessageContext(null);
+        final String rawToken = strategy.apply(prc);
+        assertNull(rawToken);
+       
+    }
+
+}

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


More information about the commits mailing list