[java-plugin-shibd-oidc] branch main updated: WIP: Refactor authorization request handlers into strategies

Phil Smart philip.smart at jisc.ac.uk
Fri Sep 26 15:55:33 UTC 2025


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

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

View the commit online:
http://git.shibboleth.net/view/?p=java-plugin-shibd-oidc.git;a=commit;h=d6c07316ac76b69b6a78113f3734b24aa7df1843

The following commit(s) were added to refs/heads/main by this push:
     new d6c0731  WIP: Refactor authorization request handlers into strategies
d6c0731 is described below

commit d6c07316ac76b69b6a78113f3734b24aa7df1843
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Fri Sep 26 16:55:31 2025 +0100

    WIP: Refactor authorization request handlers into strategies
    
     - Use strategies to locate the parameters to set
     - Move Add handlers into a seperate temporary package. These will end
    up in oidc-common
     - Create strategies to locate the parameters in the correct place e.g.
    DDF or profile. Noting, these are not complete and some will need
    fallbacks and disallow lookups
---
 .../AbstractApplicationMessageHandler.java         |   2 +-
 .../AuthenticationRequestParameterHandler.java     |  11 +-
 .../sp/oidc/profile/OIDCInitiatorConstants.java    |  33 ++--
 .../idp/flows/sp/initiator/oidc/oidc-beans.xml     | 104 ++++++++---
 .../sp/oidc/flows/OIDCAuthenticationFlowTest.java  |  97 ++++++++++
 ...actOIDCAuthenticationRequestMessageHandler.java |  94 ----------
 .../impl/AddForceAuthenticationHandler.java        |  75 --------
 .../sp/oidc/messaging/impl/AddNonceHandler.java    |  74 --------
 .../impl/AddPassiveAuthenticationHandler.java      |  60 ------
 .../oidc/messaging/impl/AddRedirectURIHandler.java |  82 ---------
 .../impl/AddResponseTypeAndModeHandler.java        | 204 ---------------------
 ...tAgentAndRelyingPartyContextLookupFunction.java | 128 +++++++++++++
 ...icationRequestParameterValueMessageHandler.java | 195 ++++++++++++++++++++
 ...enticationRequestActionMessageHandlerNOPE.java} |   8 +-
 .../AbstractProviderMetadataLookupFunction.java    |  71 +++++++
 .../impl/AuthorizationEndpointLookupStrategy.java  |  40 ++++
 .../impl/BuildPlainRequestObjectJWT.java           |  11 +-
 .../impl/DisplayParameterLookupStrategy.java       |  38 ++++
 .../impl/ForceAuthnParameterLookupStrategy.java    |  65 +++++++
 .../impl/InitializeOAuth2ClientContext.java        |   1 +
 .../oidc/profile/impl/LoginHintLookupStrategy.java |  38 ++++
 .../sp/oidc/profile/impl/MaxAgeLookupStrategy.java |  44 +++++
 .../impl/NonceLookupStrategy.java}                 |  20 +-
 .../sp/oidc/profile/impl/OIDCSupport.java          |   6 +-
 .../sp/oidc/profile/impl/PromptLookupStrategy.java |  54 ++++++
 .../profile/impl/RedirectUriLookupStrategy.java    |  53 ++++++
 .../profile/impl/ResponseModeLookupStrategy.java   |  96 ++++++++++
 .../profile/impl/ResponseTypeLookupStrategy.java   |  93 ++++++++++
 .../sp/oidc/profile/impl/ScopeLookupStrategy.java  |  49 +++++
 .../impl/SetAuthenticationRequestTimeHandler.java  |  11 +-
 .../impl/StateLookupStrategy.java}                 |  19 +-
 .../{messaging => profile}/impl/package-info.java  |   4 +-
 ...uthenticationContextClassReferencesHandler.java |   8 +-
 .../request}/impl/AddDisplayHandler.java           |  22 ++-
 .../request}/impl/AddEndpointURIHandler.java       |  17 +-
 .../impl/AddForceAuthenticationHandler.java        |  69 +++++++
 .../request}/impl/AddLoginHintHandler.java         |  14 +-
 .../request}/impl/AddMaxAgeHandler.java            |  18 +-
 .../request/impl/AddNonceHandler.java}             |  37 ++--
 .../impl/AddPCKECodeVerifierAndChallenge.java      |   7 +-
 .../profile/request/impl/AddPromptHandler.java     |  54 ++++++
 .../request/impl/AddRedirectURIHandler.java        |  56 ++++++
 .../request}/impl/AddRequestedClaimsHandler.java   |   5 +-
 .../request/impl/AddResponseModeHandler.java       | 104 +++++++++++
 .../request/impl/AddResponseTypeHandler.java       | 114 ++++++++++++
 .../request}/impl/AddScopesHandler.java            |  17 +-
 .../request}/impl/AddStateHandler.java             |  45 ++---
 .../request}/impl/package-info.java                |   4 +-
 48 files changed, 1725 insertions(+), 746 deletions(-)

diff --git a/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/messaging/AbstractApplicationMessageHandler.java b/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/messaging/AbstractApplicationMessageHandler.java
index 2796923..f380043 100644
--- a/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/messaging/AbstractApplicationMessageHandler.java
+++ b/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/messaging/AbstractApplicationMessageHandler.java
@@ -29,7 +29,7 @@ import net.shibboleth.sp.Application;
  */
 public abstract class AbstractApplicationMessageHandler extends AbstractAgentMessageHandler {
     
-    /** Cached agent from context. */
+    /** Cached Application from context. */
     @NonnullBeforeExec private Application application;
 
     /** {@inheritDoc} */
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/package-info.java b/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/profile/AuthenticationRequestParameterHandler.java
similarity index 61%
copy from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/package-info.java
copy to sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/profile/AuthenticationRequestParameterHandler.java
index 91d9f47..fb196ef 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/package-info.java
+++ b/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/profile/AuthenticationRequestParameterHandler.java
@@ -12,7 +12,14 @@
  * limitations under the License.
  */
 
+import java.util.function.Consumer;
+
+import org.opensaml.messaging.context.MessageContext;
+
 /**
- * Package that contains message handlers.
+ * A marker interface for strategies that add OIDC authentication and OAuth authorization request parameters. Operates
+ * directly on the message in the message context.
  */
-package net.shibboleth.sp.oidc.messaging.impl;
\ No newline at end of file
+public interface AuthenticationRequestParameterHandler extends Consumer<MessageContext> {
+
+}
diff --git a/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/profile/OIDCInitiatorConstants.java b/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/profile/OIDCInitiatorConstants.java
index 46ade91..107bd27 100644
--- a/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/profile/OIDCInitiatorConstants.java
+++ b/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/profile/OIDCInitiatorConstants.java
@@ -17,39 +17,38 @@ package net.shibboleth.sp.oidc.profile;
 import javax.annotation.Nonnull;
 
 import org.opensaml.saml.saml2.core.AuthnContextClassRef;
-import org.opensaml.saml.saml2.core.NameIDPolicy;
-import org.opensaml.saml.saml2.metadata.NameIDFormat;
 
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 
 /**
  * Constants for OIDC session initiator operations.
- * 
- * TODO these are not all correct for OIDC
  */
 public final class OIDCInitiatorConstants {
 
     /** ForceAuthn input parameter. */
     @Nonnull @NotEmpty public static final String FORCE_AUTHN = "forceAuthn";
-
+    
+    /** Display input parameter. */
+    @Nonnull @NotEmpty public static final String DISPLAY = "display";
+
+    /** Login_hint input parameter. */
+    @Nonnull @NotEmpty public static final String LOGIN_HINT = "login_hint";
+    
+    /** Login_hint input parameter. */
+    @Nonnull @NotEmpty public static final String MAX_AGE = "max_age";
+    
     /** IsPassive input parameter. */
     @Nonnull @NotEmpty public static final String IS_PASSIVE = "isPassive";
+    
+    /** Prompt parameter */
+    @Nonnull @NotEmpty public static final String PROMPT = "prompt";
+    
+    /** Scope parameter */
+    @Nonnull @NotEmpty public static final String SCOPE = "scope";
 
     /** authnContextClassRef input parameter. */
     @Nonnull @NotEmpty public static final String AUTHN_CONTEXT_CLASS_REF = AuthnContextClassRef.DEFAULT_ELEMENT_LOCAL_NAME;
 
-    /** authnContextComparison input parameter. */
-    @Nonnull @NotEmpty public static final String AUTHN_CONTEXT_COMPARISON = "authnContextComparison";
-
-    /** AttributeConsumingServiceIndex input parameter. */
-    @Nonnull @NotEmpty public static final String ATTRIBUTE_INDEX = "attributeIndex";
-
-    /** NameIDFormat input parameter. */
-    @Nonnull @NotEmpty public static final String NAMEID_FORMAT = NameIDFormat.DEFAULT_ELEMENT_LOCAL_NAME;
-
-    /** SPNameQualifier input parameter. */
-    @Nonnull @NotEmpty public static final String SP_NAME_QUALIFIER = NameIDPolicy.SP_NAME_QUALIFIER_ATTRIB_NAME;
-
     /** Private constructor. */
     private OIDCInitiatorConstants() {
      
diff --git a/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/oidc/oidc-beans.xml b/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/oidc/oidc-beans.xml
index 84b3c6d..4470f79 100644
--- a/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/oidc/oidc-beans.xml
+++ b/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/oidc/oidc-beans.xml
@@ -25,8 +25,10 @@
     <bean id="WebFlowOutboundMessageHandlerAdaptor"
         class="net.shibboleth.sp.profile.impl.WebFlowMessageHandlerAdaptor" scope="prototype" abstract="true"
         c:executionDirection="OUTBOUND" />
+        
+        <!-- TODO Check we need the thread-local variants of these in the chains we are using them ^^ -->
     
-    <util:constant id="shiibboleth.sp.oidc.ProfileId"
+    <util:constant id="shibboleth.sp.oidc.ProfileId"
         static-field="net.shibboleth.oidc.profile.config.OIDCSSOProfileConfiguration.PROFILE_ID" />
     <!-- end -->
     
@@ -62,7 +64,7 @@
         
     <bean id="SelectProfileConfiguration"
         class="net.shibboleth.idp.profile.impl.SelectProfileConfiguration" scope="prototype"
-        p:profileId-ref="shiibboleth.sp.oidc.ProfileId" />
+        p:profileId-ref="shibboleth.sp.oidc.ProfileId" />
         
 <!--     <bean id="InitializeOutboundMessageContext"
         class="net.shibboleth.idp.saml.profile.impl.InitializeOutboundMessageContext" scope="prototype"
@@ -87,40 +89,81 @@
             <bean class="org.opensaml.messaging.handler.impl.BasicMessageHandlerChain">
                 <property name="handlers">
                     <list>
-                        <bean id="AddResponseTypeAndMode" scope="prototype"
-                            class="net.shibboleth.sp.oidc.messaging.impl.AddResponseTypeAndModeHandler"/> 
+                        <!-- Response_type must come before response_mode -->
+                        <bean id="AddResponseType" scope="prototype"
+                            class="net.shibboleth.sp.oidc.profile.request.impl.AddResponseTypeHandler">
+                            <property name="parameterValueLookupStrategy">
+                                <bean class="net.shibboleth.sp.oidc.profile.impl.ResponseTypeLookupStrategy" scope="prototype"/>
+                            </property>
+                        </bean> 
+                        <bean id="AddResponseMode" scope="prototype"
+                            class="net.shibboleth.sp.oidc.profile.request.impl.AddResponseModeHandler">
+                            <property name="parameterValueLookupStrategy">
+                                <bean class="net.shibboleth.sp.oidc.profile.impl.ResponseModeLookupStrategy" scope="prototype"/>
+                            </property>
+                        </bean>    
+                            
                         <bean id="AddMaxAge" scope="prototype"
-                            class="net.shibboleth.sp.oidc.messaging.impl.AddMaxAgeHandler"/> 
+                            class="net.shibboleth.sp.oidc.profile.request.impl.AddMaxAgeHandler">
+                            <property name="parameterValueLookupStrategy">
+                                <bean class="net.shibboleth.sp.oidc.profile.impl.MaxAgeLookupStrategy" scope="prototype"/>
+                            </property>
+                        </bean> 
                         <bean id="AddDisplay" scope="prototype"
-                            class="net.shibboleth.sp.oidc.messaging.impl.AddDisplayHandler"/>
+                            class="net.shibboleth.sp.oidc.profile.request.impl.AddDisplayHandler" >
+                            <property name="parameterValueLookupStrategy">
+                                <bean class="net.shibboleth.sp.oidc.profile.impl.DisplayParameterLookupStrategy" scope="prototype"/>
+                            </property>
+                        </bean>
                         <bean id="AddScopes" scope="prototype"
-                            class="net.shibboleth.sp.oidc.messaging.impl.AddScopesHandler"/>
+                            class="net.shibboleth.sp.oidc.profile.request.impl.AddScopesHandler">
+                            <property name="parameterValueLookupStrategy">
+                                <bean class="net.shibboleth.sp.oidc.profile.impl.ScopeLookupStrategy" scope="prototype"/>
+                            </property>
+                        </bean>
                         <bean id="AddNonce" scope="prototype"
-                            class="net.shibboleth.sp.oidc.messaging.impl.AddNonceHandler"/>
+                            class="net.shibboleth.sp.oidc.profile.request.impl.AddNonceHandler">
+                            <property name="parameterValueLookupStrategy">
+                                <bean class="net.shibboleth.sp.oidc.profile.impl.NonceLookupStrategy" scope="prototype"/>
+                            </property>
+                        </bean>
                         <bean id="AddEndpointURI" scope="prototype"
-                            class="net.shibboleth.sp.oidc.messaging.impl.AddEndpointURIHandler"/>
+                            class="net.shibboleth.sp.oidc.profile.request.impl.AddEndpointURIHandler">
+                            <property name="parameterValueLookupStrategy">
+                                <bean class="net.shibboleth.sp.oidc.profile.impl.AuthorizationEndpointLookupStrategy" scope="prototype"/>
+                            </property>
+                        </bean>
                         <bean id="AddLoginHintHandler" scope="prototype"
-                            class="net.shibboleth.sp.oidc.messaging.impl.AddLoginHintHandler"/>
+                            class="net.shibboleth.sp.oidc.profile.request.impl.AddLoginHintHandler">
+                            <property name="parameterValueLookupStrategy">
+                                <bean class="net.shibboleth.sp.oidc.profile.impl.LoginHintLookupStrategy" scope="prototype"/>
+                            </property>
+                        </bean>
                         <bean id="AddRequestedClaims" scope="prototype"
-                            class="net.shibboleth.sp.oidc.messaging.impl.AddRequestedClaimsHandler"
+                            class="net.shibboleth.sp.oidc.profile.request.impl.AddRequestedClaimsHandler"
                             p:requestedClaimsHook="#{getObject('shibboleth.authn.oidc.rp.RequestedClaimsHook')}" />
                         <bean id="AddPCKECodeVerifierAndChallenge" scope="prototype"
-                            class="net.shibboleth.sp.oidc.messaging.impl.AddPCKECodeVerifierAndChallenge"/>                                                        
+                            class="net.shibboleth.sp.oidc.profile.request.impl.AddPCKECodeVerifierAndChallenge"/>                                                        
                         <bean id="AddRedirectURI" scope="prototype"
-                            class="net.shibboleth.sp.oidc.messaging.impl.AddRedirectURIHandler"
-                            p:httpServletRequestSupplier-ref="shibboleth.RemotedHttpServletRequestSupplier"
-                            p:redirectUriCreationStrategy="#{getObject('shibboleth.authn.oidc.rp.RedirectUriCreationStrategy') ?: 
-                                getObject('DefaultRedirectUriCreationStrategy')}" />                                
+                            class="net.shibboleth.sp.oidc.profile.request.impl.AddRedirectURIHandler">
+                            <property name="parameterValueLookupStrategy">
+                                 <bean class="net.shibboleth.sp.oidc.profile.impl.RedirectUriLookupStrategy" scope="prototype" />   
+                            </property>                         
+                        </bean>                            
                         <bean id="AddAuthenticationContextClassReferences" scope="prototype"
-                            class="net.shibboleth.sp.oidc.messaging.impl.AddAuthenticationContextClassReferencesHandler"/>
+                            class="net.shibboleth.sp.oidc.profile.request.impl.AddAuthenticationContextClassReferencesHandler"/>
                         <bean id="AddForceAuthentication" scope="prototype"
-                            class="net.shibboleth.sp.oidc.messaging.impl.AddForceAuthenticationHandler" />
-                        <!-- 
-                            Set passive authentication, prompt=none. Run after forced authentication (prompt=login) so this will take precedence 
-                            but the max_age value will be left (if forced authentication is used).
-                         -->
-                        <bean id="AddPassiveAuthentication" scope="prototype"
-                            class="net.shibboleth.sp.oidc.messaging.impl.AddPassiveAuthenticationHandler" />
+                            class="net.shibboleth.sp.oidc.profile.request.impl.AddForceAuthenticationHandler">
+                            <property name="ParameterValueLookupStrategy">
+                                <bean class="net.shibboleth.sp.oidc.profile.impl.ForceAuthnParameterLookupStrategy"/>
+                            </property>
+                        </bean>
+                        <bean id="AddPrompt" scope="prototype"
+                            class="net.shibboleth.sp.oidc.profile.request.impl.AddPromptHandler">
+                            <property name="parameterValueLookupStrategy">
+                                <bean class="net.shibboleth.sp.oidc.profile.impl.PromptLookupStrategy" scope="prototype"/>
+                            </property>
+                        </bean>
                     </list>
                 </property>
             </bean>
@@ -231,12 +274,15 @@
         scope="prototype">
         <property name="handlers">
             <list>
-                <bean id="AddState" class="net.shibboleth.sp.oidc.messaging.impl.AddStateHandler"
-                    scope="prototype"
-                    p:stateGenerationStrategy="#{getObject('shibboleth.authn.oidc.rp.StateGenerationStrategy')}" />
+                <bean id="AddState" class="net.shibboleth.sp.oidc.profile.request.impl.AddStateHandler"
+                    scope="prototype">
+                    <property name="parameterValueLookupStrategy">
+                        <bean class="net.shibboleth.sp.oidc.profile.impl.StateLookupStrategy" scope="prototype"/>
+                    </property>
+                </bean>
 
                 <bean id="BuildPlainRequestObjectJWT"
-                    class="net.shibboleth.sp.oidc.messaging.impl.BuildPlainRequestObjectJWT"
+                    class="net.shibboleth.sp.oidc.profile.impl.BuildPlainRequestObjectJWT"
                     scope="prototype" />
 
                  <bean id="SignRequestObject" class="net.shibboleth.oidc.security.impl.SignJWTHandler"
@@ -264,7 +310,7 @@
                     </property>
                 </bean>
                  <bean id="SetAuthenticationRequestTime"
-                    class="net.shibboleth.sp.oidc.messaging.impl.SetAuthenticationRequestTimeHandler" scope="prototype"/>
+                    class="net.shibboleth.sp.oidc.profile.impl.SetAuthenticationRequestTimeHandler" scope="prototype"/>
             </list>
         </property>
     </bean>
diff --git a/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCAuthenticationFlowTest.java b/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCAuthenticationFlowTest.java
index 6b13737..5b80749 100644
--- a/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCAuthenticationFlowTest.java
+++ b/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCAuthenticationFlowTest.java
@@ -120,6 +120,103 @@ public class OIDCAuthenticationFlowTest extends AbstractSPFlowTest {
         final AuthorizationRequest req = validateOutputMessage(result);
     }
     
+    /**
+     * Basic flow test with max_age.
+     * 
+     * @throws IOException on error
+     * @throws MessageDecodingException 
+     */
+    @Test
+    public void testMaxAgeFromAgent() throws IOException, MessageDecodingException {
+        setDefaultAuth();
+        
+        final DDF input = new DDF(null).structure();
+        input.addmember(RemotedHttpServletRequest.STRUCTURE_NAME).structure();        
+        input.addmember(InitiatorConstants.RESPONSE_URL).string(RESPONSE_URL);
+        input.addmember(SPConstants.TARGET).unsafe_string(RESOURCE_URL); 
+        input.addmember(OIDCInitiatorConstants.MAX_AGE).longinteger(60l);
+        setApplicationRequest("test-oidc-application", input);
+
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertFlowExecutionResult(result, FLOW_ID);
+        assertFlowExecutionOutcome(result.getOutcome());
+        
+        final AuthorizationRequest req = validateOutputMessage(result);
+    }
+    
+    /**
+     * Basic flow test with prompt=none.
+     * 
+     * @throws IOException on error
+     * @throws MessageDecodingException 
+     */
+    @Test
+    public void testPromptFromAgent() throws IOException, MessageDecodingException {
+        setDefaultAuth();
+        
+        final DDF input = new DDF(null).structure();
+        input.addmember(RemotedHttpServletRequest.STRUCTURE_NAME).structure();        
+        input.addmember(InitiatorConstants.RESPONSE_URL).string(RESPONSE_URL);
+        input.addmember(SPConstants.TARGET).unsafe_string(RESOURCE_URL); 
+        input.addmember(OIDCInitiatorConstants.PROMPT).string("none");
+        setApplicationRequest("test-oidc-application", input);
+
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertFlowExecutionResult(result, FLOW_ID);
+        assertFlowExecutionOutcome(result.getOutcome());
+        
+        final AuthorizationRequest req = validateOutputMessage(result);
+    }
+    
+    /**
+     * Basic flow test with scope=email profile.
+     * 
+     * @throws IOException on error
+     * @throws MessageDecodingException 
+     */
+    @Test
+    public void testScopeFromAgent() throws IOException, MessageDecodingException {
+        setDefaultAuth();
+        
+        final DDF input = new DDF(null).structure();
+        input.addmember(RemotedHttpServletRequest.STRUCTURE_NAME).structure();        
+        input.addmember(InitiatorConstants.RESPONSE_URL).string(RESPONSE_URL);
+        input.addmember(SPConstants.TARGET).unsafe_string(RESOURCE_URL); 
+        input.addmember(OIDCInitiatorConstants.SCOPE).string("email profile");
+        setApplicationRequest("test-oidc-application", input);
+
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertFlowExecutionResult(result, FLOW_ID);
+        assertFlowExecutionOutcome(result.getOutcome());
+        //TODO TEST THE SCOPES
+        final AuthorizationRequest req = validateOutputMessage(result);
+    }
+    
+    
+    /**
+     * Basic flow test with display.
+     * 
+     * @throws IOException on error
+     * @throws MessageDecodingException 
+     */
+    @Test
+    public void testDisplayFromAgent() throws IOException, MessageDecodingException {
+        setDefaultAuth();
+        
+        final DDF input = new DDF(null).structure();
+        input.addmember(RemotedHttpServletRequest.STRUCTURE_NAME).structure();        
+        input.addmember(InitiatorConstants.RESPONSE_URL).string(RESPONSE_URL);
+        input.addmember(SPConstants.TARGET).unsafe_string(RESOURCE_URL); 
+        input.addmember(OIDCInitiatorConstants.DISPLAY).string("page");
+        setApplicationRequest("test-oidc-application", input);
+
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertFlowExecutionResult(result, FLOW_ID);
+        assertFlowExecutionOutcome(result.getOutcome());
+        
+        final AuthorizationRequest req = validateOutputMessage(result);
+    }
+    
     /**
      * Decode an encoded response and run sanity checks against it.
      * 
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AbstractOIDCAuthenticationRequestMessageHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AbstractOIDCAuthenticationRequestMessageHandler.java
deleted file mode 100644
index a8771f8..0000000
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AbstractOIDCAuthenticationRequestMessageHandler.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.sp.oidc.messaging.impl;
-
-import java.util.function.Function;
-
-import javax.annotation.Nonnull;
-
-import org.opensaml.messaging.context.MessageContext;
-import org.opensaml.messaging.handler.AbstractMessageHandler;
-import org.opensaml.messaging.handler.MessageHandlerException;
-import org.slf4j.Logger;
-
-import net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest;
-import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
-import net.shibboleth.shared.logic.Constraint;
-import net.shibboleth.shared.primitive.LoggerFactory;
-
-/** 
- * An abstract message handler that makes available the {@link OIDCAuthenticationRequest}.
- */
-public abstract class AbstractOIDCAuthenticationRequestMessageHandler extends AbstractMessageHandler {
-
-    /** Class logger. */
-    @Nonnull private final Logger log = LoggerFactory.getLogger(AbstractOIDCAuthenticationRequestMessageHandler.class);
-    
-    /** Strategy used to locate the {@link OIDCAuthenticationRequest}.  */
-    @Nonnull private Function<MessageContext, OIDCAuthenticationRequest> authenticationRequestLookupStrategy;
-    
-    
-    /** The stashed {@link OIDCAuthenticationRequest}.*/
-    @NonnullBeforeExec private OIDCAuthenticationRequest authnRequest;
-    
-    /** Constructor.*/
-    protected AbstractOIDCAuthenticationRequestMessageHandler() {
-        
-        authenticationRequestLookupStrategy = mc -> {
-            if (mc.getMessage() instanceof final OIDCAuthenticationRequest request) {
-                return request;
-            }
-            return null;
-        };
-    }
-    
-    /**
-     * Get the authentication request.
-     * 
-     * @return the authentication request
-     */
-    @NonnullBeforeExec protected OIDCAuthenticationRequest getAuthenticationRequest() {
-        return authnRequest;
-    }
-
-    /**
-     * Set the strategy used to locate the {@link OIDCAuthenticationRequest} to use.
-     * 
-     * @param strategy lookup strategy
-     */
-    public void setAuthenticationRequestLookupStrategy(
-            @Nonnull final Function<MessageContext, OIDCAuthenticationRequest> strategy) {
-    	checkSetterPreconditions();
-
-        authenticationRequestLookupStrategy =
-                Constraint.isNotNull(strategy, "AuthenticationRequestLookupStrategy lookup strategy cannot be null");
-    }
-    
-    @Override
-    protected boolean doPreInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException {
-
-        authnRequest = authenticationRequestLookupStrategy.apply(messageContext);
-        if (authnRequest == null) {
-            log.debug("{} OIDC authentication request is null", getLogPrefix());
-            throw new MessageHandlerException("OIDC authentication request is null");
-        }
-        
-        return super.doPreInvoke(messageContext);
-    }
-
-    
-    
-
-}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddForceAuthenticationHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddForceAuthenticationHandler.java
deleted file mode 100644
index 6e1025c..0000000
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddForceAuthenticationHandler.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.sp.oidc.messaging.impl;
-
-import java.time.Duration;
-
-import javax.annotation.Nonnull;
-
-import org.opensaml.messaging.context.MessageContext;
-import org.opensaml.messaging.handler.MessageHandlerException;
-import org.slf4j.Logger;
-
-import com.nimbusds.oauth2.sdk.ParseException;
-import com.nimbusds.openid.connect.sdk.Prompt;
-
-import net.shibboleth.shared.primitive.LoggerFactory;
-import net.shibboleth.sp.oidc.profile.OIDCInitiatorConstants;
-
-/** 
- * An action that sets the 'prompt' parameter to 'login' and max_age to 0 seconds, iff force authn was requested by the 
- * upstream SP (or is overridden in the profile config).
- */
-public class AddForceAuthenticationHandler extends AbstractOIDCAuthenticationRequestActionMessageHandler {
-    
-    /** Class logger. */
-    @Nonnull private final Logger log = LoggerFactory.getLogger(AddForceAuthenticationHandler.class);
-    
-    @Override protected void doInvoke(@Nonnull final MessageContext messageContext) 
-            throws MessageHandlerException {
-        
-        final Integer forceAuthn = getInput().getmember(OIDCInitiatorConstants.FORCE_AUTHN).integer();
-        
-        if (forceAuthn != null) {
-            // TODO disallow feature if set but not allowed
-            try {
-                getAuthenticationRequest().setPrompt(Prompt.parse(Prompt.Type.LOGIN.toString()));
-                getAuthenticationRequest().setMaxAge(Duration.ofSeconds(0));
-            } catch (final ParseException e) {
-                // This should never happen
-                throw new MessageHandlerException("Unable to honour force-authn, "
-                        + "setting prompt to force-login as failed", e);
-            }
-            return;
-        }
-        // Else try from Profile config
-        if (getProfileConfiguration().isForceAuthn(lookupProfileRequestContext(messageContext))) {
-            log.trace("{} Setting prompt=login and max_age=0 (ForceAuthn) for OIDC AuthnRequest", getLogPrefix());
-            try {
-                getAuthenticationRequest().setPrompt(Prompt.parse(Prompt.Type.LOGIN.toString()));
-                getAuthenticationRequest().setMaxAge(Duration.ofSeconds(0));
-            } catch (final ParseException e) {
-                // This should never happen
-                throw new MessageHandlerException("Unable to honour force-authn, "
-                        + "setting prompt to force-login as failed", e);
-            }
-        } else {
-            log.trace("{} No ForceAuthn requirement, so no prompt or max_age set", getLogPrefix());
-        }
-    }
-    
-    
-
-}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddNonceHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddNonceHandler.java
deleted file mode 100644
index 948a0b0..0000000
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddNonceHandler.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.sp.oidc.messaging.impl;
-
-import java.util.function.Function;
-
-import javax.annotation.Nonnull;
-
-import org.opensaml.messaging.context.MessageContext;
-import org.opensaml.messaging.handler.MessageHandlerException;
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.slf4j.Logger;
-
-import com.nimbusds.openid.connect.sdk.Nonce;
-
-import net.shibboleth.shared.logic.Constraint;
-import net.shibboleth.shared.primitive.LoggerFactory;
-import net.shibboleth.sp.oidc.profile.impl.OIDCSupport;
-
-/** 
- * A message handler that adds a nonce from a lookup strategy to the authentication request.
- * The injected nonce generation strategy could generate a {@literal null} nonce.
- */
-public class AddNonceHandler extends AbstractOIDCAuthenticationRequestActionMessageHandler {
-    
-    /** Class logger. */
-    @Nonnull private final Logger log = LoggerFactory.getLogger(AddNonceHandler.class);
-    
-    /** Strategy used to generate a nonce. Could generate a {@literal null} nonce.*/
-    @Nonnull private Function<ProfileRequestContext, Nonce> nonceGenerationStrategy;
-    
-    /** Constructor.*/
-    public AddNonceHandler() {
-        // Simple strategy that uses a secure random implementation to generate a nonce of length 16
-        nonceGenerationStrategy = prc -> new Nonce(OIDCSupport.generateNonce(16));
-    }
-    
-    /**
-     * Set the nonce generation strategy to use.
-     * 
-     * @param strategy the strategy
-     */
-    public void setNonceGenerationStrategy(@Nonnull final Function<ProfileRequestContext, Nonce> strategy) {
-    	checkSetterPreconditions();
-        
-        nonceGenerationStrategy = Constraint.isNotNull(strategy, "Nonce generation strategy can not be null");
-    }
-    
-    @Override protected void doInvoke(@Nonnull final MessageContext messageContext) 
-            throws MessageHandlerException {
-        
-        
-        getAuthenticationRequest().setNonce(
-                nonceGenerationStrategy.apply(lookupProfileRequestContext(messageContext)));
-        
-        log.trace("{} Added nonce '{}' to authentication request",getLogPrefix(),
-                getAuthenticationRequest().getNonce());
-    }
-    
-    
-
-}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddPassiveAuthenticationHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddPassiveAuthenticationHandler.java
deleted file mode 100644
index 2a4e63b..0000000
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddPassiveAuthenticationHandler.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.sp.oidc.messaging.impl;
-
-import javax.annotation.Nonnull;
-
-import org.opensaml.messaging.context.MessageContext;
-import org.opensaml.messaging.handler.MessageHandlerException;
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.slf4j.Logger;
-
-import com.nimbusds.oauth2.sdk.ParseException;
-import com.nimbusds.openid.connect.sdk.Prompt;
-
-import net.shibboleth.idp.authn.context.AuthenticationContext;
-import net.shibboleth.shared.primitive.LoggerFactory;
-
-/** 
- * A message handler that sets the 'prompt' parameter to 'none' if passive authentication has been requested by the
- * SP.
- */
-public class AddPassiveAuthenticationHandler extends AbstractOIDCAuthenticationRequestActionMessageHandler {
-    
-    /** Class logger. */
-    @Nonnull private final Logger log = LoggerFactory.getLogger(AddPassiveAuthenticationHandler.class);
-    
-    @Override protected void doInvoke(@Nonnull final MessageContext messageContext) 
-            throws MessageHandlerException {
-        
-        final ProfileRequestContext prc = lookupProfileRequestContext(messageContext);
-        boolean isPassive = false;
-        if (prc != null && prc.getParent() instanceof final AuthenticationContext authnContext) {
-            isPassive = authnContext.isPassive();
-        }
-        if (isPassive) {
-            log.trace("{} Setting 'prompt=none' for OIDC AuthnRequest", getLogPrefix());
-            try {
-                getAuthenticationRequest().setPrompt(Prompt.parse(Prompt.Type.NONE.toString()));
-            } catch (final ParseException e) {
-              // This should never happen
-              throw new MessageHandlerException("Unable to honour passive authentication requirement, "
-                      + "setting prompt to 'none' has failed", e);
-          }
-        } else {
-            log.trace("{} No passive authentication requirement, so prompt=none has not been set", getLogPrefix());
-        }
-    }
-}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddRedirectURIHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddRedirectURIHandler.java
deleted file mode 100644
index 8955161..0000000
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddRedirectURIHandler.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.sp.oidc.messaging.impl;
-
-import java.net.URI;
-import java.util.function.BiFunction;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import org.opensaml.messaging.context.MessageContext;
-import org.opensaml.messaging.handler.MessageHandlerException;
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.slf4j.Logger;
-
-import jakarta.servlet.http.HttpServletRequest;
-import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
-import net.shibboleth.shared.component.ComponentInitializationException;
-import net.shibboleth.shared.logic.Constraint;
-import net.shibboleth.shared.primitive.LoggerFactory;
-
-/** 
- * A message handler that adds a redirect_uri to the authentication request.
- */
-public class AddRedirectURIHandler extends AbstractOIDCAuthenticationRequestActionMessageHandler {
-
-    /** Logger. */
-    @Nonnull private final Logger log = LoggerFactory.getLogger(AddRedirectURIHandler.class);
-    
-    /** Function to create a suitable redirect URI from the given servlet request and profile request context.*/
-    @NonnullAfterInit private BiFunction<HttpServletRequest, ProfileRequestContext, URI> redirectUriCreationStrategy;
-        
-    /**
-     * Set the creation strategy used to compute or lookup a redirect URI.
-     * 
-     * @param strategy the creation strategy
-     */
-    public void setRedirectUriCreationStrategy(
-            @Nullable final BiFunction<HttpServletRequest, ProfileRequestContext, URI> strategy) {
-    	checkSetterPreconditions();
-        
-        if (strategy != null) {
-            redirectUriCreationStrategy = 
-                Constraint.isNotNull(strategy, "RedirectURI creation lookup strategy cannot be null");
-        }
-    }
-    
-    @Override
-    protected void doInitialize() throws ComponentInitializationException {
-        super.doInitialize();
-        
-        if (redirectUriCreationStrategy == null) {
-            throw new ComponentInitializationException("redirectUriCreationStrategy cannot be null");
-        }
-    }
-
-    @Override protected void doInvoke(@Nonnull final MessageContext messageContext) 
-            throws MessageHandlerException {   
-       
-        final URI redirectUri = 
-                redirectUriCreationStrategy.apply(getHttpServletRequest(), lookupProfileRequestContext(messageContext));
-        if (redirectUri == null) {
-            throw new MessageHandlerException("Redirect URI could not be located or created using the strategy");
-        }
-        log.trace("{} Created redirect_uri '{}'", getLogPrefix(), redirectUri);
-        getAuthenticationRequest().setRedirectURI(redirectUri);
-  
-    }
-
-}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddResponseTypeAndModeHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddResponseTypeAndModeHandler.java
deleted file mode 100644
index e19585a..0000000
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddResponseTypeAndModeHandler.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.sp.oidc.messaging.impl;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import org.opensaml.messaging.context.MessageContext;
-import org.opensaml.messaging.handler.MessageHandlerException;
-import org.slf4j.Logger;
-
-import com.nimbusds.oauth2.sdk.ResponseMode;
-import com.nimbusds.oauth2.sdk.ResponseType;
-
-import net.shibboleth.shared.primitive.LoggerFactory;
-
-/**
- * A message handler that populates the authentication request response_mode and response_type from various strategies, 
- * by default from the profile configuration.
- * 
- *  <p>Unless explicitly set, the default response_mode for the specified response_type will be used.</p> 
- */
-public class AddResponseTypeAndModeHandler extends AbstractOIDCAuthenticationRequestActionMessageHandler {
-    
-    /** Class logger. */
-    @Nonnull private final Logger log = LoggerFactory.getLogger(AddResponseTypeAndModeHandler.class);
-    
-    
-    @Override protected void doInvoke(@Nonnull final MessageContext messageContext) 
-                throws MessageHandlerException {
-        
-        final String responseTypeFromProfile = 
-                getProfileConfiguration().getResponseType(lookupProfileRequestContext(messageContext)); 
-        final ResponseType responseType = parseResponseType(responseTypeFromProfile);
-        if (responseType == null){
-            throw new MessageHandlerException("response_type '"+responseTypeFromProfile+"' is not supported");
-        }
-        // Check is supported by the provider
-        checkProviderSupportsResponseType(responseType);
-       
-        final String responseModeFromProfile = 
-                getProfileConfiguration().getResponseMode(lookupProfileRequestContext(messageContext)); 
-        final ResponseMode responseModeOverride = parseResponseMode(responseModeFromProfile);
-        log.trace("{} response mode override from profile config '{}', parsed as '{}'",getLogPrefix(), responseModeFromProfile, 
-                responseModeOverride);
-                
-        final ResponseMode compatibleMode = ResponseMode.resolve(null, responseType);
-        if (compatibleMode == null) {
-            throw new MessageHandlerException("A compatible response_mode for response_type "
-                    + "'"+responseType+"' could not be found");
-        }
-        
-        checkProviderSupportsResponseMode(compatibleMode);
-        
-        log.trace("{} Compatible response_mode '{}' resolved from response_type '{}'", getLogPrefix(), compatibleMode, 
-                responseTypeFromProfile);    
-        getAuthenticationRequest().setDefaultResponseMode(compatibleMode);
-            
-        if (responseModeOverride != null && !responseModeOverride.equals(compatibleMode)) {
-            log.debug("{} response_mode override '{}' exists in the profile configuration and is different than the"
-                    + " default mode '{}' for response_type '{}'",
-                    getLogPrefix(), responseModeFromProfile, compatibleMode, responseType);  
-            
-            checkProviderSupportsResponseMode(responseModeOverride);
-            getAuthenticationRequest().setResponseMode(responseModeOverride);
-            
-        } else {
-            getAuthenticationRequest().setResponseMode(compatibleMode);
-        }
-        
-        getAuthenticationRequest().setResponseType(responseType); 
-        log.trace("{} response_type '{}' selected", getLogPrefix(), getAuthenticationRequest().getResponseType());
-        log.trace("{} response_mode '{}' selected", getLogPrefix(), getAuthenticationRequest().getResponseMode());
-            
-    }
-    
-    /**
-     * Check the OpenID Provider supports the response_type from its metadata value response_types_supported. Throws
-     * an exception if not.
-     * 
-     * @param responseType the response_type to check is supported
-     * 
-     * @throws MessageHandlerException if the OpenID Provider does not support the response_type
-     */
-    private void checkProviderSupportsResponseType(@Nonnull final ResponseType responseType) 
-            throws MessageHandlerException {
-        final List<ResponseType> responseTypesSupported = getProviderMetadata().getResponseTypes();
-        if (responseTypesSupported == null) {
-            throw new MessageHandlerException("OpenID Provider has not specified supported response types "
-                    + "(response_types_supported). It MUST.");
-        }
-        if (!responseTypesSupported.contains(responseType)) {
-            throw new MessageHandlerException("OpenID Provider does not support chosen response_type: "
-                    + responseType.toString());
-        }
-    }
-    
-    /**
-     * Check the OpenID Provider supports the response_mode from its metadata value response_modes_supported. Throws
-     * an exception if not.
-     * 
-     * @param responseMode the response_mode to check is supported
-     * 
-     * @throws MessageHandlerException if the OpenID Provider does not support the response_mode
-     */
-    private void checkProviderSupportsResponseMode(@Nonnull final ResponseMode responseMode) 
-            throws MessageHandlerException {
-        final List<ResponseMode> responseModesSupportedOP = getProviderMetadata().getResponseModes();
-        final List<ResponseMode> responseModesSupported = new ArrayList<>(2);
-        if (responseModesSupportedOP == null || responseModesSupportedOP.isEmpty()) {
-            // Add the defaults from the specification
-            responseModesSupported.add(ResponseMode.QUERY);
-            responseModesSupported.add(ResponseMode.FRAGMENT);
-        } else {
-            responseModesSupportedOP.forEach(responseModesSupported::add);
-        }
-        if (!responseModesSupported.contains(responseMode)) {
-            throw new MessageHandlerException("OpenID Provider does not support chosen response_mode: "
-                    + responseMode.toString());
-        }
-        
-    }
-    
-    /**
-     * Parse the response_type into a known {@link ResponseType}.
-     * 
-     * @param responseTypeFromProfile the response_type as a string
-     * 
-     * @return the parsed {@link ResponseType}, or {@literal null} if the input type is unknown
-     */
-    @Nullable private ResponseType parseResponseType(@Nullable final String responseTypeFromProfile) {
-        
-        if (responseTypeFromProfile == null) {
-            return null;
-        }
-
-        if (responseTypeFromProfile.equals(ResponseType.CODE.toString())) {
-            return ResponseType.CODE;
-        } else if (responseTypeFromProfile.equals(ResponseType.CODE_IDTOKEN.toString())) {
-            return ResponseType.CODE_IDTOKEN; 
-        } else if (responseTypeFromProfile.equals(ResponseType.CODE_IDTOKEN_TOKEN.toString())) {
-            return ResponseType.CODE_IDTOKEN_TOKEN;
-        } else if (responseTypeFromProfile.equals(ResponseType.CODE_TOKEN.toString())) {
-            return ResponseType.CODE_TOKEN;
-        } else if (responseTypeFromProfile.equals(ResponseType.IDTOKEN.toString())) {
-            return ResponseType.IDTOKEN;
-        } else if (responseTypeFromProfile.equals(ResponseType.IDTOKEN_TOKEN.toString())) {
-            return ResponseType.IDTOKEN_TOKEN;
-        } else {
-            return null;
-        }
-    }
-    
- // Checkstyle: ReturnCount OFF
-    /**
-     * Parse the response_mode into a known {@link ResponseMode}.
-     * 
-     * @param responseModeFromProfile the response_mode as a string
-     * 
-     * @return the parsed {@link ResponseMode}, or {@literal null} if the input type is unknown
-     */
-    @Nullable private ResponseMode parseResponseMode(@Nullable final String responseModeFromProfile) {
-        
-        if (responseModeFromProfile == null) {
-            return null;
-        }
-        
-        if (responseModeFromProfile.equals(ResponseMode.FORM_POST.getValue())) {
-            return ResponseMode.FORM_POST;
-        } else if (responseModeFromProfile.equals(ResponseMode.FORM_POST_JWT.getValue())) {
-            return ResponseMode.FORM_POST_JWT;
-        } else if (responseModeFromProfile.equals(ResponseMode.QUERY.getValue())) {
-            return ResponseMode.QUERY;
-        } else if (responseModeFromProfile.equals(ResponseMode.FRAGMENT.getValue())) {
-            return ResponseMode.FRAGMENT;
-        } else if (responseModeFromProfile.equals(ResponseMode.FRAGMENT_JWT.getValue())) {
-            return ResponseMode.FRAGMENT_JWT;
-        } else if (responseModeFromProfile.equals(ResponseMode.JWT.getValue())) {
-            return ResponseMode.JWT;
-        } else if (responseModeFromProfile.equals(ResponseMode.QUERY_JWT.getValue())) {
-            return ResponseMode.QUERY_JWT;
-        } else {
-            return null;
-        }
-    }
- // Checkstyle: ReturnCount ON
-    
-
-}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AbstractAgentAndRelyingPartyContextLookupFunction.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AbstractAgentAndRelyingPartyContextLookupFunction.java
new file mode 100644
index 0000000..1884432
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AbstractAgentAndRelyingPartyContextLookupFunction.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.messaging.context.navigate.ParentContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.profile.context.navigate.messaging.AbstractRelyingPartyLookupFunction;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.sp.Agent;
+import net.shibboleth.sp.Application;
+import net.shibboleth.sp.context.AgentRequestContext;
+import net.shibboleth.sp.ddf.DDF;
+
+/**
+ *
+ * Abstract base class for a function that requires a {@link AgentRequestContext}
+ * obtained via a lookup function, by default a child of the {@link ProfileRequestContext}.
+ * 
+ * @param <ResultType> return type of function
+ */
+public abstract class AbstractAgentAndRelyingPartyContextLookupFunction<ResultType>
+                                        extends AbstractRelyingPartyLookupFunction<ResultType>{
+    
+    /** Lookup strategy for {@link AgentRequestContext}. */
+    @Nonnull private Function<MessageContext,AgentRequestContext> agentRequestContextLookupStrategy;
+    
+    /** Either the input or output DDF message from the agent.*/
+    protected enum DDFDirection {
+        /** The input message from the agent.*/
+        INPUT,
+        /** The output message for the agent.*/
+        OUTPUT
+    }
+    
+    protected AbstractAgentAndRelyingPartyContextLookupFunction() {
+        // By default msgCtx (up)-> ProfileRequestContext (down)-> AgentRequestContext 
+        agentRequestContextLookupStrategy = new ChildContextLookup<>(AgentRequestContext.class)
+                .compose(new ParentContextLookup<>(ProfileRequestContext.class));
+    }
+    
+    /**
+     * Sets the lookup strategy for the {@link AgentRequestContext}.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setAgentRequestContextLookupStrategy(
+            @Nonnull final Function<MessageContext,AgentRequestContext> strategy) {        
+        agentRequestContextLookupStrategy = Constraint.isNotNull(strategy,
+                "AgentRequestContext lookup strategy cannot be null");
+    }
+    
+    /**
+     * Invokes the installed lookup function to locate the {@link AgentRequestContext}.
+     * 
+     * @param input the message context
+     * 
+     * @return the {@link AgentRequestContext} or null
+     */
+    @Nullable protected AgentRequestContext getAgentRequestContext(@Nullable final MessageContext input) {
+        return agentRequestContextLookupStrategy.apply(input); 
+    }
+    
+    /**
+     * Gets the {@link Agent} for this request.
+     * 
+     * @return the agent
+     */
+    @Nullable public Agent getAgent(@Nullable final MessageContext input) {
+        final AgentRequestContext arc = agentRequestContextLookupStrategy.apply(input);
+        if (arc == null) {
+            return null;
+        }
+        return arc.getAgent();
+    }
+    
+    /**
+     * Gets the {@link Application} for this request.
+     * 
+     * @return the agent
+     */
+    @Nullable public Application getApplication(@Nullable final MessageContext input) {
+        final AgentRequestContext arc = agentRequestContextLookupStrategy.apply(input);
+        if (arc == null) {
+            return null;
+        }
+        return arc.getApplication();        
+    }
+    
+    /**
+     * Gets the {@link DDF} for this request, either the input from the agent or the output for the agent.
+     * 
+     * @return the input or output DDF
+     */
+    @Nullable public DDF getDDF(@Nullable final MessageContext input, @Nonnull final DDFDirection direction) {
+        final AgentRequestContext arc = agentRequestContextLookupStrategy.apply(input);
+        if (arc == null) {
+            return null;
+        }
+        switch (direction) {
+            case INPUT:
+                return arc.getInput();
+            case OUTPUT:
+                return arc.getOutput();
+            default:
+                return null; 
+        }
+    }
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AbstractAuthenticationRequestParameterValueMessageHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AbstractAuthenticationRequestParameterValueMessageHandler.java
new file mode 100644
index 0000000..3d9a4a7
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AbstractAuthenticationRequestParameterValueMessageHandler.java
@@ -0,0 +1,195 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.messaging.handler.AbstractMessageHandler;
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.slf4j.Logger;
+
+import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
+
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
+import net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest;
+import net.shibboleth.oidc.profile.messaging.context.OIDCPeerEntityContext;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+/** 
+ * Base class for message handlers that process and apply values of OpenID Connect authentication request parameters.
+ * 
+ * <p>
+ * This abstract class provides common functionality for locating:
+ * </p>
+ * <ul>
+ *   <li>the {@link OIDCAuthenticationRequest} associated with the current
+ *       {@link MessageContext},</li>
+ *   <li>the {@link OIDCProviderMetadata} describing the peer OpenID Provider,</li>
+ *   <li>and the parameter value to be extracted and validated against
+ *       the expected Java type.</li>
+ * </ul>
+ * </p>
+ * 
+ * @param <T> the authentication request parameter value type
+ */
+public abstract class AbstractAuthenticationRequestParameterValueMessageHandler<T> extends AbstractMessageHandler {
+
+    /** Class logger. */
+    @Nonnull private final Logger log = 
+            LoggerFactory.getLogger(AbstractAuthenticationRequestParameterValueMessageHandler.class);
+    
+    /** Strategy used to locate the {@link OIDCAuthenticationRequest}.  */
+    @Nonnull private Function<MessageContext, OIDCAuthenticationRequest> authenticationRequestLookupStrategy;
+    
+    /** Lookup strategy to locate the OpenID Provider metadata to use.*/
+    @Nonnull private Function<MessageContext, OIDCProviderMetadataContext> providerMetadataLookupStrategy;
+    
+    @Nullable private Function<MessageContext, T> parameterValueLookupStrategy;
+    
+    /** The authentication request parameter value type.*/
+    @Nonnull private Class<T> type;
+    
+    /** The stashed {@link OIDCAuthenticationRequest}.*/
+    @NonnullBeforeExec private OIDCAuthenticationRequest authnRequest;  
+    
+    /** The stashed OpenID Provider metadata .*/
+    @NonnullBeforeExec private OIDCProviderMetadata providerMetadata;
+    
+    
+    /** Constructor.*/
+    protected AbstractAuthenticationRequestParameterValueMessageHandler(@Nonnull final Class<T> valueType) {
+        type = Constraint.isNotNull(valueType, "Authentication request parameter value type cannot be null");
+        authenticationRequestLookupStrategy = mc -> {
+            if (mc.getMessage() instanceof final OIDCAuthenticationRequest request) {
+                return request;
+            }
+            return null;
+        };
+        providerMetadataLookupStrategy = new ChildContextLookup<>(OIDCProviderMetadataContext.class).compose(
+                new ChildContextLookup<>(OIDCPeerEntityContext.class));  
+    }
+    
+    /**
+     * Get the authentication request.
+     * 
+     * @return the authentication request
+     */
+    @NonnullBeforeExec protected OIDCAuthenticationRequest getAuthenticationRequest() {
+        return authnRequest;
+    }
+    
+    /**
+     * Set the lookup strategy to locate the OpenID providers metadata.
+     * 
+     * @param strategy the strategy.
+     */
+    public void setProviderMetadataLookupStrategy(
+            @Nonnull final Function<MessageContext, OIDCProviderMetadataContext> strategy) {
+        checkSetterPreconditions();
+        
+        providerMetadataLookupStrategy = 
+                Constraint.isNotNull(strategy,"Provider metadata lookup strategy can not be null");
+    }
+    
+    /**
+     * Returns the OpenID Provider metadata. Should never be {@code null} after
+     * after {@code doPreExecute} has been called.
+     * 
+     * @return The provider metadata context.
+     */
+    @NonnullBeforeExec protected OIDCProviderMetadata getProviderMetadata() {
+        return providerMetadata;
+    }
+    
+    /**
+     * Set the parameter value lookup strategy used to find the value to set onto the authentication request.
+     * 
+     * @param strategy The parameter value lookup strategy to set.
+     */
+    public void setParameterValueLookupStrategy(final Function<MessageContext, T> strategy) {
+        checkSetterPreconditions();
+        parameterValueLookupStrategy = Constraint.isNotNull(strategy,
+                "ParameterValueLookupStrategy can not be null");
+    }
+    
+    /**
+     * Retrieves the parameter value from the configured lookup strategy, 
+     * verifying at runtime that the result matches the type expected by 
+     * the subclass.
+     *  
+     * @param context the message context to pass to the lookup function
+     * 
+     * @return the parameter value
+     * 
+     * @throws MessageHandlerException if the value is not the expected type
+     */
+    @Nullable protected T getParameterValue(final MessageContext context) 
+            throws MessageHandlerException {
+        final var localParameterValueLookupStrategy = parameterValueLookupStrategy;
+        if (localParameterValueLookupStrategy == null) {
+            return null;
+        }
+        final Object value = localParameterValueLookupStrategy.apply(context);
+        if (value == null) {
+            return null;
+        }
+        if (type.isInstance(value)) {
+            return type.cast(value);
+        }
+        throw new MessageHandlerException("Authentication request parameter value lookup returned the "
+                + "wrong value type");
+    }
+
+    /**
+     * Set the strategy used to locate the {@link OIDCAuthenticationRequest} to use.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setAuthenticationRequestLookupStrategy(
+            @Nonnull final Function<MessageContext, OIDCAuthenticationRequest> strategy) {
+    	checkSetterPreconditions();
+
+        authenticationRequestLookupStrategy =
+                Constraint.isNotNull(strategy, "AuthenticationRequestLookupStrategy lookup strategy cannot be null");
+    }
+    
+    @Override
+    protected boolean doPreInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException {
+
+        authnRequest = authenticationRequestLookupStrategy.apply(messageContext);
+        if (authnRequest == null) {
+            throw new MessageHandlerException("OIDC authentication request is null");
+        }
+        final OIDCProviderMetadataContext providerMetadataContext = 
+                providerMetadataLookupStrategy.apply(messageContext);
+        if (providerMetadataContext == null) {
+            throw new MessageHandlerException("No provider metadata context found for peer");
+        }
+        providerMetadata = providerMetadataContext.getProviderInformation();
+        if (providerMetadata == null) {
+            throw new MessageHandlerException("No provider metadata found for peer");
+        }
+        
+        return super.doPreInvoke(messageContext);
+    }
+
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AbstractOIDCAuthenticationRequestActionMessageHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AbstractOIDCAuthenticationRequestActionMessageHandlerNOPE.java
similarity index 98%
rename from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AbstractOIDCAuthenticationRequestActionMessageHandler.java
rename to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AbstractOIDCAuthenticationRequestActionMessageHandlerNOPE.java
index 1c1fb0f..de73cd8 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AbstractOIDCAuthenticationRequestActionMessageHandler.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AbstractOIDCAuthenticationRequestActionMessageHandlerNOPE.java
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.sp.oidc.messaging.impl;
+package net.shibboleth.sp.oidc.profile.impl;
 
 import java.util.function.Function;
 import java.util.function.Predicate;
@@ -50,7 +50,7 @@ import net.shibboleth.sp.oidc.messaging.AbstractApplicationMessageHandler;
  * <p>The {@link MessageContext} will either be INBOUND or OUTBOUND depending on the direction defined
  * by the calling {@link WebFlowMessageHandlerAdaptor} action.</p>
  */
-public abstract class AbstractOIDCAuthenticationRequestActionMessageHandler extends AbstractApplicationMessageHandler {    
+public abstract class AbstractOIDCAuthenticationRequestActionMessageHandlerNOPE extends AbstractApplicationMessageHandler {    
     
     /** Lookup function for parent ProfileRequestContext. */
     @Nonnull private static final ParentProfileRequestContextLookup<MessageContext> PRC_LOOKUP
@@ -58,7 +58,7 @@ public abstract class AbstractOIDCAuthenticationRequestActionMessageHandler exte
     
     /** Class logger. */
     @Nonnull private final Logger log = 
-            LoggerFactory.getLogger(AbstractOIDCAuthenticationRequestActionMessageHandler.class);
+            LoggerFactory.getLogger(AbstractOIDCAuthenticationRequestActionMessageHandlerNOPE.class);
     
     /** Lookup strategy to locate the OpenID Provider metadata to use.*/
     @Nonnull private Function<MessageContext, OIDCProviderMetadataContext> providerMetadataLookupStrategy;
@@ -82,7 +82,7 @@ public abstract class AbstractOIDCAuthenticationRequestActionMessageHandler exte
     @NonnullBeforeExec private DDF input;
     
     /** Constructor.*/
-    protected AbstractOIDCAuthenticationRequestActionMessageHandler() {
+    protected AbstractOIDCAuthenticationRequestActionMessageHandlerNOPE() {
         providerMetadataLookupStrategy = new ChildContextLookup<>(OIDCProviderMetadataContext.class).compose(
                 new ChildContextLookup<>(OIDCPeerEntityContext.class));        
         relyingPartyContextLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AbstractProviderMetadataLookupFunction.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AbstractProviderMetadataLookupFunction.java
new file mode 100644
index 0000000..1e6660f
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AbstractProviderMetadataLookupFunction.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.BaseContext;
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+
+import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
+
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
+import net.shibboleth.oidc.profile.messaging.context.OIDCPeerEntityContext;
+import net.shibboleth.shared.logic.Constraint;
+
+/**
+ * An abstract base class for pulling out the Provider metadata
+ */
+public abstract class AbstractProviderMetadataLookupFunction<F extends BaseContext, T> implements Function<F, T> {
+    
+    /** Lookup strategy to locate the OpenID Provider metadata to use.*/
+    @Nonnull private Function<MessageContext, OIDCProviderMetadataContext> providerMetadataLookupStrategy;
+    
+    /** Constructor.*/
+    protected AbstractProviderMetadataLookupFunction() {
+        providerMetadataLookupStrategy = new ChildContextLookup<>(OIDCProviderMetadataContext.class).compose(
+                new ChildContextLookup<>(OIDCPeerEntityContext.class));
+    }
+    
+    /**
+     * Set the lookup strategy to locate the OpenID providers metadata.
+     * 
+     * @param strategy the strategy.
+     */
+    public void setProviderMetadataLookupStrategy(
+            @Nonnull final Function<MessageContext, OIDCProviderMetadataContext> strategy) {
+        
+        providerMetadataLookupStrategy = 
+                Constraint.isNotNull(strategy,"Provider metadata lookup strategy can not be null");
+    }
+    
+    /**
+    * Gets the {@link OIDCProviderMetadata} for this request.
+    * 
+    * @return the provider's metadata
+    */
+   @Nullable public OIDCProviderMetadata getProviderMetadata(@Nullable final MessageContext input) {
+       final OIDCProviderMetadataContext providerCtx = providerMetadataLookupStrategy.apply(input);
+       if (providerCtx == null) {
+           return null;
+       }
+       return providerCtx.getProviderInformation();
+   }
+
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AuthorizationEndpointLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AuthorizationEndpointLookupStrategy.java
new file mode 100644
index 0000000..988f8ad
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/AuthorizationEndpointLookupStrategy.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.impl;
+
+import java.net.URI;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+
+import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
+
+/**
+ * Get the OAuth 2.0 authorization endpoint from the OpenID Provider metadata.
+ */
+public class AuthorizationEndpointLookupStrategy 
+    extends AbstractProviderMetadataLookupFunction<MessageContext, URI> {
+
+    /** {@inheritDoc} */
+    @Nullable public URI apply(final MessageContext messageCtx) {
+        final OIDCProviderMetadata metadata = getProviderMetadata(messageCtx);
+        if (metadata == null) {
+            return null;
+        }
+        return metadata.getAuthorizationEndpointURI();
+    }
+
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/BuildPlainRequestObjectJWT.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/BuildPlainRequestObjectJWT.java
similarity index 87%
rename from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/BuildPlainRequestObjectJWT.java
rename to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/BuildPlainRequestObjectJWT.java
index 313861f..8b6cfd2 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/BuildPlainRequestObjectJWT.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/BuildPlainRequestObjectJWT.java
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.sp.oidc.messaging.impl;
+package net.shibboleth.sp.oidc.profile.impl;
 
 import javax.annotation.Nonnull;
 
@@ -30,11 +30,18 @@ import net.shibboleth.shared.primitive.LoggerFactory;
  * If the Request Object claims are present in the authentication request, convert them 
  * into a JWTClaimsSet inside a PlainJWT. 
  */
-public class BuildPlainRequestObjectJWT extends AbstractOIDCAuthenticationRequestMessageHandler {
+public class BuildPlainRequestObjectJWT extends AbstractAuthenticationRequestParameterValueMessageHandler<ClaimsSet> {
 
     /** Logger. */
     @Nonnull
     private final Logger log = LoggerFactory.getLogger(BuildPlainRequestObjectJWT.class);
+   
+    /**
+     * Constructor.
+     */
+    protected BuildPlainRequestObjectJWT() {
+        super(ClaimsSet.class);
+    }
 
     /** {@inheritDoc} */
     @Override
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/DisplayParameterLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/DisplayParameterLookupStrategy.java
new file mode 100644
index 0000000..55c0e0d
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/DisplayParameterLookupStrategy.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.impl;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+
+import net.shibboleth.sp.ddf.DDF;
+import net.shibboleth.sp.oidc.profile.OIDCInitiatorConstants;
+
+/**
+ * Retrieve the 'display' parameter from the {@link DDF}.
+ */
+public class DisplayParameterLookupStrategy extends AbstractAgentAndRelyingPartyContextLookupFunction<String> {
+
+    /** {@inheritDoc} */
+    @Nullable public String apply(final MessageContext messageCtx) {
+        final DDF input = getDDF(messageCtx, DDFDirection.INPUT);
+        if (input == null) {
+            return null;
+        }
+        return input.getmember(OIDCInitiatorConstants.DISPLAY).string();
+    }
+
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ForceAuthnParameterLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ForceAuthnParameterLookupStrategy.java
new file mode 100644
index 0000000..0f93fb7
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ForceAuthnParameterLookupStrategy.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.impl;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+
+import net.shibboleth.sp.ddf.DDF;
+import net.shibboleth.sp.oidc.profile.OIDCInitiatorConstants;
+
+/**
+ * Retrieve the ForceAuthn parameter from the {@link DDF}.
+ */
+public class ForceAuthnParameterLookupStrategy extends AbstractAgentAndRelyingPartyContextLookupFunction<Boolean> {
+
+    /** {@inheritDoc} */
+    @Nullable public Boolean apply(final MessageContext messageCtx) {
+        final DDF input = getDDF(messageCtx, DDFDirection.INPUT);
+        if (input == null) {
+            return null;
+        }
+        final Integer forceAuthn = input.getmember(OIDCInitiatorConstants.FORCE_AUTHN).integer();
+        
+        if (forceAuthn != null) {
+            // TODO disallow feature if set but not allowed
+//            if (profileConfiguration.isFeatureDisallowed(profileRequestContext,
+//                    BrowserSSOProfileConfiguration.FEATURE_FORCEAUTHN)) {
+//                log.warn("{} Agent disallowed from overriding ForceAuthn", getLogPrefix());
+//            } 
+            if (forceAuthn == 1) {
+                return true;
+            }
+            return false;
+        }
+        return false;
+        // Else try from Profile config
+//        if (getProfileConfiguration().isForceAuthn(lookupProfileRequestContext(messageContext))) {
+//            log.trace("{} Setting prompt=login and max_age=0 (ForceAuthn) for OIDC AuthnRequest", getLogPrefix());
+//            try {
+//                getAuthenticationRequest().setPrompt(Prompt.parse(Prompt.Type.LOGIN.toString()));
+//                getAuthenticationRequest().setMaxAge(Duration.ofSeconds(0));
+//            } catch (final ParseException e) {
+//                // This should never happen
+//                throw new MessageHandlerException("Unable to honour force-authn, "
+//                        + "setting prompt to force-login as failed", e);
+//            }
+//        } else {
+//            log.trace("{} No ForceAuthn requirement, so no prompt or max_age set", getLogPrefix());
+//        }
+    }
+
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/InitializeOAuth2ClientContext.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/InitializeOAuth2ClientContext.java
index d27de46..2f17886 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/InitializeOAuth2ClientContext.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/InitializeOAuth2ClientContext.java
@@ -48,6 +48,7 @@ import net.shibboleth.sp.oidc.context.OAuth2ClientContext;
  * @post Add the clientId and redirect URI to the {@link OAuth2ClientContext}
  */
 // TODO this mostly pulls in things from the profile config and stores them, it could just come from the profile later
+//TODO Client ID needs to come from the issuer which is in the BasicAgent of the relying party config 
 public class InitializeOAuth2ClientContext extends AbstractProfileAction {
 
     /** Class logger. */
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/LoginHintLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/LoginHintLookupStrategy.java
new file mode 100644
index 0000000..8f45297
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/LoginHintLookupStrategy.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.impl;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+
+import net.shibboleth.sp.ddf.DDF;
+import net.shibboleth.sp.oidc.profile.OIDCInitiatorConstants;
+
+/**
+ * Retrieve the 'login_hint' parameter from the {@link DDF}.
+ */
+public class LoginHintLookupStrategy extends AbstractAgentAndRelyingPartyContextLookupFunction<String> {
+
+    /** {@inheritDoc} */
+    @Nullable public String apply(final MessageContext messageCtx) {
+        final DDF input = getDDF(messageCtx, DDFDirection.INPUT);
+        if (input == null) {
+            return null;
+        }
+        return input.getmember(OIDCInitiatorConstants.LOGIN_HINT).string();
+    }
+
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/MaxAgeLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/MaxAgeLookupStrategy.java
new file mode 100644
index 0000000..0f00321
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/MaxAgeLookupStrategy.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.impl;
+
+import java.time.Duration;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+
+import net.shibboleth.sp.ddf.DDF;
+import net.shibboleth.sp.oidc.profile.OIDCInitiatorConstants;
+
+/**
+ * Retrieve the max_age parameter from the {@link DDF}.
+ */
+public class MaxAgeLookupStrategy extends AbstractAgentAndRelyingPartyContextLookupFunction<Duration> {
+
+    /** {@inheritDoc} */
+    @Nullable public Duration apply(final MessageContext messageCtx) {
+        final DDF input = getDDF(messageCtx, DDFDirection.INPUT);
+        if (input == null) {
+            return null;
+        }
+        final Long maxAge = input.getmember(OIDCInitiatorConstants.MAX_AGE).longinteger();
+        if (maxAge == null) {
+            return null;
+        }
+        return Duration.ofSeconds(maxAge);
+    }
+
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/package-info.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/NonceLookupStrategy.java
similarity index 51%
copy from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/package-info.java
copy to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/NonceLookupStrategy.java
index 91d9f47..72b949d 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/package-info.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/NonceLookupStrategy.java
@@ -12,7 +12,23 @@
  * limitations under the License.
  */
 
+package net.shibboleth.sp.oidc.profile.impl;
+
+import java.util.function.Function;
+
+import org.opensaml.messaging.context.MessageContext;
+
+import com.nimbusds.openid.connect.sdk.Nonce;
+
 /**
- * Package that contains message handlers.
+ * A simple strategy that uses a secure random implementation to generate a nonce of length 16.
  */
-package net.shibboleth.sp.oidc.messaging.impl;
\ No newline at end of file
+public class NonceLookupStrategy implements Function<MessageContext, Nonce> {
+
+    /** {@inheritDoc} */
+    @Override
+    public Nonce apply(final MessageContext message) {        
+        return new Nonce(OIDCSupport.generateRandom(16));
+    }
+
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/OIDCSupport.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/OIDCSupport.java
index 3ad6057..22066c1 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/OIDCSupport.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/OIDCSupport.java
@@ -31,13 +31,13 @@ public final class OIDCSupport {
     }
     
     /**
-     * Generates a random identifier to be used as a nonce.
+     * Generates a random identifier, encoded in Hex..
      *  
      * @param length the length of the parameter.
      * 
-     * @return the randomly generated nonce value.
+     * @return the randomly generated Hex value.
      */
-    @Nonnull public static String generateNonce(@Nonnull final Integer length) {
+    @Nonnull public static String generateRandom(@Nonnull final Integer length) {
         final SecureRandom secureRandom = new SecureRandom();
         final StringBuilder sb = new StringBuilder();
         while(sb.length() < length){
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/PromptLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/PromptLookupStrategy.java
new file mode 100644
index 0000000..5bb7962
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/PromptLookupStrategy.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.impl;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.slf4j.Logger;
+
+import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.openid.connect.sdk.Prompt;
+
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.ddf.DDF;
+import net.shibboleth.sp.oidc.profile.OIDCInitiatorConstants;
+
+/**
+ * Retrieve the Prompt parameter from the {@link DDF}.
+ */
+public class PromptLookupStrategy extends AbstractAgentAndRelyingPartyContextLookupFunction<Prompt> {
+    
+    /** Logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(PromptLookupStrategy.class);
+
+    /** {@inheritDoc} */
+    @Nullable public Prompt apply(final MessageContext messageCtx) {
+        final DDF input = getDDF(messageCtx, DDFDirection.INPUT);
+        if (input == null) {
+            return null;
+        }
+        final String promptFromDDF = input.getmember(OIDCInitiatorConstants.PROMPT).string();
+        try {
+            return Prompt.parse(promptFromDDF);
+        } catch (final ParseException e) {
+            // This should never happen
+            log.error("Unable parse Prompt from DDF", e);
+            return null;
+        }
+    }
+
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/RedirectUriLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/RedirectUriLookupStrategy.java
new file mode 100644
index 0000000..72393f5
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/RedirectUriLookupStrategy.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.impl;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.slf4j.Logger;
+
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.ddf.DDF;
+import net.shibboleth.sp.profile.InitiatorConstants;
+
+/**
+ * Retrieve the 'redirect_uri' parameter from the 'response_url' in the {@link DDF}.
+ */
+public class RedirectUriLookupStrategy extends AbstractAgentAndRelyingPartyContextLookupFunction<URI> {
+    
+    /** Logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(RedirectUriLookupStrategy.class);
+
+    /** {@inheritDoc} */
+    @Nullable public URI apply(final MessageContext messageCtx) {
+        final DDF input = getDDF(messageCtx, DDFDirection.INPUT);
+        if (input == null) {
+            return null;
+        }
+        final String responseUrlFromDDF = input.getmember(InitiatorConstants.RESPONSE_URL).string();
+        try {
+            return new URI(responseUrlFromDDF);
+        } catch (final URISyntaxException e) {
+            log.error("Unable to create a redirect URI from the response_url in the input DDF", e);
+            return null;
+        }
+    }
+
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ResponseModeLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ResponseModeLookupStrategy.java
new file mode 100644
index 0000000..c6e2f10
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ResponseModeLookupStrategy.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.impl;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.profile.context.navigate.ParentProfileRequestContextLookup;
+
+import com.nimbusds.oauth2.sdk.ResponseMode;
+
+import net.shibboleth.oidc.profile.config.OIDCAuthenticationRelyingPartyProfileConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+
+/**
+ * A lookup strategy that resolves an OpenID Connect {@link ResponseMode} from the current {@link MessageContext}.
+ * <p>
+ * This strategy inspects the active {@link RelyingPartyContext} and its associated
+ * {@link OIDCAuthenticationRelyingPartyProfileConfiguration}. If a response mode
+ * is configured in the relying party profile, it is parsed into a known
+ * {@link ResponseMode} value. If no configuration is available or the configured
+ * value does not map to a supported response mode, the lookup returns {@code null}.
+ * </p>
+ */
+public class ResponseModeLookupStrategy extends AbstractAgentAndRelyingPartyContextLookupFunction<ResponseMode> {
+    
+    /** Lookup function for parent ProfileRequestContext. */
+    @Nonnull private static final ParentProfileRequestContextLookup<MessageContext> PRC_LOOKUP
+        = new ParentProfileRequestContextLookup<>();
+
+    /** {@inheritDoc} */
+    @Override
+    public ResponseMode apply(final MessageContext messageContext) {
+        
+        final RelyingPartyContext rpc = getRelyingPartyContext(messageContext);
+        
+        if (!(rpc != null && rpc.getProfileConfig() 
+                instanceof final OIDCAuthenticationRelyingPartyProfileConfiguration rpConfig)) {
+            return null;
+        }
+        // If there is no other path, and the compiler can prove rpConfig is true, you can use it here.
+        final String responseModeFromProfile = 
+                rpConfig.getResponseMode(PRC_LOOKUP.apply(messageContext)); 
+        return parseResponseMode(responseModeFromProfile);
+    }
+    
+    
+    // Checkstyle: ReturnCount OFF
+    /**
+     * Parse the response_mode into a known {@link ResponseMode}.
+     * 
+     * @param responseModeFromProfile the response_mode as a string
+     * 
+     * @return the parsed {@link ResponseMode}, or {@literal null} if the input type is unknown
+     */
+    @Nullable private ResponseMode parseResponseMode(@Nullable final String responseModeFromProfile) {
+        
+        if (responseModeFromProfile == null) {
+            return null;
+        }
+        
+        if (responseModeFromProfile.equals(ResponseMode.FORM_POST.getValue())) {
+            return ResponseMode.FORM_POST;
+        } else if (responseModeFromProfile.equals(ResponseMode.FORM_POST_JWT.getValue())) {
+            return ResponseMode.FORM_POST_JWT;
+        } else if (responseModeFromProfile.equals(ResponseMode.QUERY.getValue())) {
+            return ResponseMode.QUERY;
+        } else if (responseModeFromProfile.equals(ResponseMode.FRAGMENT.getValue())) {
+            return ResponseMode.FRAGMENT;
+        } else if (responseModeFromProfile.equals(ResponseMode.FRAGMENT_JWT.getValue())) {
+            return ResponseMode.FRAGMENT_JWT;
+        } else if (responseModeFromProfile.equals(ResponseMode.JWT.getValue())) {
+            return ResponseMode.JWT;
+        } else if (responseModeFromProfile.equals(ResponseMode.QUERY_JWT.getValue())) {
+            return ResponseMode.QUERY_JWT;
+        } else {
+            return null;
+        }
+    }
+ // Checkstyle: ReturnCount ON
+    
+
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ResponseTypeLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ResponseTypeLookupStrategy.java
new file mode 100644
index 0000000..2c28d32
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ResponseTypeLookupStrategy.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.impl;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.context.navigate.ParentProfileRequestContextLookup;
+
+import com.nimbusds.oauth2.sdk.ResponseType;
+
+import net.shibboleth.oidc.profile.config.OIDCAuthenticationRelyingPartyProfileConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+
+/**
+ * A lookup strategy that resolves the {@link ResponseType} to use
+ * for a relying party, based the {@link OIDCAuthenticationRelyingPartyProfileConfiguration}.
+ * 
+ *  A lookup strategy that resolves an OpenID Connect {@link ResponseType} from the current {@link MessageContext}.
+ * <p>
+ * This strategy inspects the active {@link RelyingPartyContext} and its associated
+ * {@link OIDCAuthenticationRelyingPartyProfileConfiguration}. If a response type
+ * is configured in the relying party profile, it is parsed into a known
+ * {@link ResponseType} value. If no configuration is available or the configured
+ * value does not map to a supported response type, the lookup returns {@code null}.
+ * </p>
+ */
+public class ResponseTypeLookupStrategy extends AbstractAgentAndRelyingPartyContextLookupFunction<ResponseType>{
+    
+    /** Lookup function for parent {@link ProfileRequestContext}. */
+    @Nonnull private static final ParentProfileRequestContextLookup<MessageContext> PRC_LOOKUP
+        = new ParentProfileRequestContextLookup<>();
+
+    /** {@inheritDoc} */
+    @Override
+    public ResponseType apply(@Nullable final MessageContext messageContext) {
+        final RelyingPartyContext rpc = getRelyingPartyContext(messageContext);
+        
+        if (!(rpc != null && rpc.getProfileConfig() 
+                instanceof final OIDCAuthenticationRelyingPartyProfileConfiguration rpConfig)) {
+            return null;
+        }
+        // If there is no other path, and the compiler can prove rpConfig is true, you can use it here.
+        final String responseTypeFromProfile = 
+                rpConfig.getResponseType(PRC_LOOKUP.apply(messageContext)); 
+        return parseResponseType(responseTypeFromProfile);
+    }
+    
+    
+    /**
+     * Parse a {@code response_type} into a known {@link ResponseType}.
+     * 
+     * @param responseTypeFromProfile the response_type as a string
+     * 
+     * @return the parsed {@link ResponseType}, or {@literal null} if the input type is unknown
+     */
+    @Nullable private ResponseType parseResponseType(@Nullable final String responseTypeFromProfile) {
+        
+        if (responseTypeFromProfile == null) {
+            return null;
+        }
+
+        if (responseTypeFromProfile.equals(ResponseType.CODE.toString())) {
+            return ResponseType.CODE;
+        } else if (responseTypeFromProfile.equals(ResponseType.CODE_IDTOKEN.toString())) {
+            return ResponseType.CODE_IDTOKEN; 
+        } else if (responseTypeFromProfile.equals(ResponseType.CODE_IDTOKEN_TOKEN.toString())) {
+            return ResponseType.CODE_IDTOKEN_TOKEN;
+        } else if (responseTypeFromProfile.equals(ResponseType.CODE_TOKEN.toString())) {
+            return ResponseType.CODE_TOKEN;
+        } else if (responseTypeFromProfile.equals(ResponseType.IDTOKEN.toString())) {
+            return ResponseType.IDTOKEN;
+        } else if (responseTypeFromProfile.equals(ResponseType.IDTOKEN_TOKEN.toString())) {
+            return ResponseType.IDTOKEN_TOKEN;
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ScopeLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ScopeLookupStrategy.java
new file mode 100644
index 0000000..2e485e5
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ScopeLookupStrategy.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.impl;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.opensaml.messaging.context.MessageContext;
+
+import net.shibboleth.shared.primitive.StringSupport;
+import net.shibboleth.sp.ddf.DDF;
+import net.shibboleth.sp.oidc.profile.OIDCInitiatorConstants;
+
+/**
+ *
+ */
+public class ScopeLookupStrategy extends AbstractAgentAndRelyingPartyContextLookupFunction<Set<String>>{
+
+    /** {@inheritDoc} */
+    @Override
+    public Set<String> apply(final MessageContext messageContext) {
+        final DDF input = getDDF(messageContext, DDFDirection.INPUT);
+        if (input == null) {
+            return null;
+        }
+        final String scopeFromDDF = input.getmember(OIDCInitiatorConstants.SCOPE).string();
+        if (StringSupport.trimOrNull(scopeFromDDF) == null) {
+            return null;
+        }
+        assert scopeFromDDF != null;
+        return Arrays.stream(scopeFromDDF.split("\\s+"))
+                .filter(s -> !s.isEmpty())
+                .collect(Collectors.toUnmodifiableSet());
+    }
+
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/SetAuthenticationRequestTimeHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/SetAuthenticationRequestTimeHandler.java
similarity index 85%
rename from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/SetAuthenticationRequestTimeHandler.java
rename to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/SetAuthenticationRequestTimeHandler.java
index 13d802f..51bdeba 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/SetAuthenticationRequestTimeHandler.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/SetAuthenticationRequestTimeHandler.java
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.sp.oidc.messaging.impl;
+package net.shibboleth.sp.oidc.profile.impl;
 
 import java.time.Instant;
 
@@ -26,11 +26,18 @@ import net.shibboleth.shared.primitive.LoggerFactory;
 
 
 /** Handler that adds the authentication request time to the authentication request.*/
-public class SetAuthenticationRequestTimeHandler extends AbstractOIDCAuthenticationRequestMessageHandler {
+public class SetAuthenticationRequestTimeHandler extends AbstractAuthenticationRequestParameterValueMessageHandler<Instant> {
     
     /** Logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(SetAuthenticationRequestTimeHandler.class);
     
+    /**
+     * Constructor.
+     */
+    protected SetAuthenticationRequestTimeHandler() {
+        super(Instant.class);
+    }
+    
     /** {@inheritDoc} */
     @Override
     protected void doInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException {        
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/package-info.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/StateLookupStrategy.java
similarity index 52%
copy from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/package-info.java
copy to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/StateLookupStrategy.java
index 91d9f47..60008a0 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/package-info.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/StateLookupStrategy.java
@@ -12,7 +12,22 @@
  * limitations under the License.
  */
 
+package net.shibboleth.sp.oidc.profile.impl;
+
+import java.util.function.Function;
+
+import org.opensaml.messaging.context.MessageContext;
+
 /**
- * Package that contains message handlers.
+ * A simple strategy that uses a secure random implementation to generate a state of length 32.
  */
-package net.shibboleth.sp.oidc.messaging.impl;
\ No newline at end of file
+public class StateLookupStrategy implements Function<MessageContext, String> {
+
+    /** {@inheritDoc} */
+    @Override
+    public String apply(final MessageContext message) {  
+        // By default, generate a 32 character state.     
+        return OIDCSupport.generateRandom(32);
+    }
+
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/package-info.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/package-info.java
similarity index 85%
copy from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/package-info.java
copy to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/package-info.java
index 91d9f47..2e5696f 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/package-info.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/package-info.java
@@ -13,6 +13,6 @@
  */
 
 /**
- * Package that contains message handlers.
+ * OIDC Relying Party profile implementation classes.
  */
-package net.shibboleth.sp.oidc.messaging.impl;
\ No newline at end of file
+package net.shibboleth.sp.oidc.profile.impl;
\ No newline at end of file
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddAuthenticationContextClassReferencesHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddAuthenticationContextClassReferencesHandler.java
similarity index 93%
rename from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddAuthenticationContextClassReferencesHandler.java
rename to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddAuthenticationContextClassReferencesHandler.java
index 50410c4..f24a1e1 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddAuthenticationContextClassReferencesHandler.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddAuthenticationContextClassReferencesHandler.java
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.sp.oidc.messaging.impl;
+package net.shibboleth.sp.oidc.profile.request.impl;
 
 import java.security.Principal;
 import java.util.List;
@@ -29,13 +29,13 @@ import com.nimbusds.openid.connect.sdk.claims.ACR;
 
 import net.shibboleth.oidc.profile.config.navigate.ProxyAwareDefaultOIDCAuthenticationContextClassRequestLookupFunction;
 import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.oidc.profile.impl.AbstractOIDCAuthenticationRequestActionMessageHandlerNOPE;
 
 /** 
- * A message handler that adds any authentication context class references from the those derived from the
- * profile config - which may be proxied and mapped from the original request.
+ * A message handler that adds any authentication context class references. TODO
  */
 public class AddAuthenticationContextClassReferencesHandler 
-                extends AbstractOIDCAuthenticationRequestActionMessageHandler {
+                extends AbstractOIDCAuthenticationRequestActionMessageHandlerNOPE {
 
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(AddAuthenticationContextClassReferencesHandler.class);
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddDisplayHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddDisplayHandler.java
similarity index 76%
rename from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddDisplayHandler.java
rename to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddDisplayHandler.java
index 2bb6683..538f7d7 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddDisplayHandler.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddDisplayHandler.java
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.sp.oidc.messaging.impl;
+package net.shibboleth.sp.oidc.profile.request.impl;
 
 import javax.annotation.Nonnull;
 
@@ -25,31 +25,33 @@ import com.nimbusds.openid.connect.sdk.Display;
 
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.primitive.StringSupport;
+import net.shibboleth.sp.oidc.profile.impl.AbstractAuthenticationRequestParameterValueMessageHandler;
 
 
 /** 
- * Message handler that adds the optional 'display' request parameter if manually set on the profile configuration. 
- * 
- * @since 2.1.0
+ * Message handler that adds the optional 'display' request parameter. 
  */
-public class AddDisplayHandler extends AbstractOIDCAuthenticationRequestActionMessageHandler {
+public class AddDisplayHandler extends AbstractAuthenticationRequestParameterValueMessageHandler<String> {
 
     /** Logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(AddDisplayHandler.class);
+    
+    /** Constructor. */
+    protected AddDisplayHandler() {
+        super(String.class);
+    }
 
     @Override protected void doInvoke(@Nonnull final MessageContext messageContext) 
             throws MessageHandlerException {   
        
-       final String display = getProfileConfiguration().getDisplay(lookupProfileRequestContext(messageContext));
-       if (StringSupport.trimOrNull(display) != null) {           
+       final String display = getParameterValue(messageContext);
+       if (StringSupport.trimOrNull(display) != null) {    
            try {
                getAuthenticationRequest().setDisplay(Display.parse(display));
                log.trace("Adding 'display' request parameter value '{}'", display);
             } catch (final ParseException e) {
                 throw new MessageHandlerException("Unable to add a 'display' value of: " + display);
             }
-       }
-  
+       }  
     }
-
 }
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddEndpointURIHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddEndpointURIHandler.java
similarity index 68%
copy from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddEndpointURIHandler.java
copy to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddEndpointURIHandler.java
index 0606dfa..0188d6e 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddEndpointURIHandler.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddEndpointURIHandler.java
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.sp.oidc.messaging.impl;
+package net.shibboleth.sp.oidc.profile.request.impl;
 
 import java.net.URI;
 
@@ -23,24 +23,29 @@ import org.opensaml.messaging.handler.MessageHandlerException;
 import org.slf4j.Logger;
 
 import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.oidc.profile.impl.AbstractAuthenticationRequestParameterValueMessageHandler;
 
 
 /** 
- * A message handler that adds the authorization endpoint URI from the providers metadata 
- * to the under constructions authentication request. If an authorization endpoint does
+ * A message handler that adds the authorization endpoint URI. If an authorization endpoint does
  * not exist, an exception is thrown.
  */
-public class AddEndpointURIHandler extends AbstractOIDCAuthenticationRequestActionMessageHandler {
+public class AddEndpointURIHandler extends AbstractAuthenticationRequestParameterValueMessageHandler<URI> {
     
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(AddEndpointURIHandler.class);
     
+    /** Constructor.*/
+    public AddEndpointURIHandler() {
+        super(URI.class);
+    }
+    
     @Override protected void doInvoke(@Nonnull final MessageContext messageContext) 
             throws MessageHandlerException {
         
-        final URI authzEndpoint = getProviderMetadata().getAuthorizationEndpointURI();
+        final URI authzEndpoint = getParameterValue(messageContext);
         if (authzEndpoint == null) {
-            throw new MessageHandlerException("OAuth 2.0 Authorization Endpoint URI not found in provider metadata");
+            throw new MessageHandlerException("OAuth 2.0 authorization endpoint URI not found in provider metadata");
         }
         
         getAuthenticationRequest().setEndpointURI(authzEndpoint);
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddForceAuthenticationHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddForceAuthenticationHandler.java
new file mode 100644
index 0000000..c4ab0af
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddForceAuthenticationHandler.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.request.impl;
+
+import java.time.Duration;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.slf4j.Logger;
+
+import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.openid.connect.sdk.Prompt;
+
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.oidc.profile.impl.AbstractAuthenticationRequestParameterValueMessageHandler;
+
+/**
+ * An action that sets the 'prompt' parameter to 'login' and max_age to 0
+ * seconds, iff force authn was requested by the upstream SP (or is overridden
+ * in the profile config).
+ */
+public class AddForceAuthenticationHandler extends AbstractAuthenticationRequestParameterValueMessageHandler<Boolean> {
+
+    /** Class logger. */
+    @Nonnull
+    private final Logger log = LoggerFactory.getLogger(AddForceAuthenticationHandler.class);
+
+    /**
+     * Constructor.
+     */
+    protected AddForceAuthenticationHandler() {
+        super(Boolean.class);
+    }
+
+    @Override
+    protected void doInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException {
+
+        final Boolean isForceAuthn = getParameterValue(messageContext);
+        if (isForceAuthn != null && isForceAuthn) {
+            log.trace("{} Setting prompt=login and max_age=0 (ForceAuthn) for OIDC AuthnRequest", getLogPrefix());
+            try {
+                getAuthenticationRequest().setPrompt(Prompt.parse(Prompt.Type.LOGIN.toString()));
+                getAuthenticationRequest().setMaxAge(Duration.ofSeconds(0));
+            } catch (final ParseException e) {
+                // This should never happen
+                throw new MessageHandlerException(
+                        "Unable to honour force-authn, " + "setting prompt to force-login as failed", e);
+            }
+        } else {
+            log.trace("{} No ForceAuthn requirement, so no prompt or max_age set", getLogPrefix());
+        }
+
+    }
+
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddLoginHintHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddLoginHintHandler.java
similarity index 72%
rename from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddLoginHintHandler.java
rename to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddLoginHintHandler.java
index c4482bc..0eda163 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddLoginHintHandler.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddLoginHintHandler.java
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.sp.oidc.messaging.impl;
+package net.shibboleth.sp.oidc.profile.request.impl;
 
 import javax.annotation.Nonnull;
 
@@ -21,19 +21,23 @@ import org.opensaml.messaging.handler.MessageHandlerException;
 import org.slf4j.Logger;
 
 import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.oidc.profile.impl.AbstractAuthenticationRequestParameterValueMessageHandler;
 
 
-/** Message handler that adds the login_hint parameter based on any defined in the profile configuration.*/
-public class AddLoginHintHandler extends AbstractOIDCAuthenticationRequestActionMessageHandler {
+/** Message handler that adds the login_hint parameter.*/
+public class AddLoginHintHandler extends AbstractAuthenticationRequestParameterValueMessageHandler<String> {
     
     /** Logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(AddLoginHintHandler.class);
+    
+    public AddLoginHintHandler() {
+        super(String.class);
+    }
 
     @Override
     protected void doInvoke(final MessageContext messageContext) throws MessageHandlerException {
         
-        final String loginHint = 
-                getProfileConfiguration().getLoginHint(lookupProfileRequestContext(messageContext));
+        final String loginHint = getParameterValue(messageContext);
         
         if (loginHint != null) {
             log.trace("{} Added login_hint parameter '{}'", getLogPrefix(), loginHint);
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddMaxAgeHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddMaxAgeHandler.java
similarity index 72%
rename from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddMaxAgeHandler.java
rename to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddMaxAgeHandler.java
index edfc045..a70c9aa 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddMaxAgeHandler.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddMaxAgeHandler.java
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.sp.oidc.messaging.impl;
+package net.shibboleth.sp.oidc.profile.request.impl;
 
 import java.time.Duration;
 
@@ -23,25 +23,27 @@ import org.opensaml.messaging.handler.MessageHandlerException;
 import org.slf4j.Logger;
 
 import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.oidc.profile.impl.AbstractAuthenticationRequestParameterValueMessageHandler;
 
 
-/** Message handler that adds the max_age parameter based on any defined in the profile configuration.*/
-public class AddMaxAgeHandler extends AbstractOIDCAuthenticationRequestActionMessageHandler {
+/** Message handler that adds the max_age parameter.*/
+public class AddMaxAgeHandler extends AbstractAuthenticationRequestParameterValueMessageHandler<Duration> {
 
     /** Logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(AddMaxAgeHandler.class);
+    
+    public AddMaxAgeHandler() {
+        super(Duration.class);
+    }
 
     @Override protected void doInvoke(@Nonnull final MessageContext messageContext) 
             throws MessageHandlerException {   
        
-        final Duration maxAge = 
-                getProfileConfiguration().getMaxAuthenticationAge(lookupProfileRequestContext(messageContext));
+        final Duration maxAge = getParameterValue(messageContext);
         
         if (maxAge != null) {
             log.trace("{} Added max_age parameter '{}'", getLogPrefix(), maxAge);
             getAuthenticationRequest().setMaxAge(maxAge);
-        }
-  
+        }  
     }
-
 }
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddEndpointURIHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddNonceHandler.java
similarity index 54%
rename from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddEndpointURIHandler.java
rename to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddNonceHandler.java
index 0606dfa..c81261e 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddEndpointURIHandler.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddNonceHandler.java
@@ -12,9 +12,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.sp.oidc.messaging.impl;
-
-import java.net.URI;
+package net.shibboleth.sp.oidc.profile.request.impl;
 
 import javax.annotation.Nonnull;
 
@@ -22,29 +20,36 @@ import org.opensaml.messaging.context.MessageContext;
 import org.opensaml.messaging.handler.MessageHandlerException;
 import org.slf4j.Logger;
 
-import net.shibboleth.shared.primitive.LoggerFactory;
+import com.nimbusds.openid.connect.sdk.Nonce;
 
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.oidc.profile.impl.AbstractAuthenticationRequestParameterValueMessageHandler;
 
 /** 
- * A message handler that adds the authorization endpoint URI from the providers metadata 
- * to the under constructions authentication request. If an authorization endpoint does
- * not exist, an exception is thrown.
+ * A message handler that adds a nonce from a lookup strategy to the authentication request.
+ * The nonce can be {@literal null}.
  */
-public class AddEndpointURIHandler extends AbstractOIDCAuthenticationRequestActionMessageHandler {
+public class AddNonceHandler extends AbstractAuthenticationRequestParameterValueMessageHandler<Nonce> {
     
     /** Class logger. */
-    @Nonnull private final Logger log = LoggerFactory.getLogger(AddEndpointURIHandler.class);
+    @Nonnull private final Logger log = LoggerFactory.getLogger(AddNonceHandler.class);
+    
+    /** Constructor.*/
+    public AddNonceHandler() {
+        super(Nonce.class);
+    }
     
     @Override protected void doInvoke(@Nonnull final MessageContext messageContext) 
             throws MessageHandlerException {
         
-        final URI authzEndpoint = getProviderMetadata().getAuthorizationEndpointURI();
-        if (authzEndpoint == null) {
-            throw new MessageHandlerException("OAuth 2.0 Authorization Endpoint URI not found in provider metadata");
+        final Nonce nonce = getParameterValue(messageContext);
+        if (nonce != null) {
+            getAuthenticationRequest().setNonce(nonce);
+            log.trace("{} Added nonce '{}' to authentication request",getLogPrefix(),
+                    getAuthenticationRequest().getNonce());
         }
-        
-        getAuthenticationRequest().setEndpointURI(authzEndpoint);
-        log.trace("{} Added authorization endpoint '{}' to authentication request",getLogPrefix(),
-                getAuthenticationRequest().getEndpointURI());
     }
+    
+    
+
 }
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddPCKECodeVerifierAndChallenge.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddPCKECodeVerifierAndChallenge.java
similarity index 96%
rename from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddPCKECodeVerifierAndChallenge.java
rename to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddPCKECodeVerifierAndChallenge.java
index 19d5dd0..c4a2ea1 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddPCKECodeVerifierAndChallenge.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddPCKECodeVerifierAndChallenge.java
@@ -13,7 +13,7 @@
  */
 
 
-package net.shibboleth.sp.oidc.messaging.impl;
+package net.shibboleth.sp.oidc.profile.request.impl;
 
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
@@ -30,14 +30,13 @@ import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.codec.Base64Support;
 import net.shibboleth.shared.codec.EncodingException;
 import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.oidc.profile.impl.AbstractOIDCAuthenticationRequestActionMessageHandlerNOPE;
 
 /**
  * Create an OAuth 2.0 PCKE code_verifier to use in the token request, and derives a code_challenge for immediate use in
  * the authorization request.
- * 
- * @since 2.1.0
  */
-public class AddPCKECodeVerifierAndChallenge extends AbstractOIDCAuthenticationRequestActionMessageHandler {
+public class AddPCKECodeVerifierAndChallenge extends AbstractOIDCAuthenticationRequestActionMessageHandlerNOPE {
     
     /** Logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(AddPCKECodeVerifierAndChallenge.class);
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddPromptHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddPromptHandler.java
new file mode 100644
index 0000000..65ee9b5
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddPromptHandler.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.request.impl;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.slf4j.Logger;
+
+import com.nimbusds.openid.connect.sdk.Prompt;
+
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.oidc.profile.impl.AbstractAuthenticationRequestParameterValueMessageHandler;
+
+/**
+ * A message handler that sets the 'prompt' parameter to 'none' if passive
+ * authentication has been requested by the SP.
+ */
+public class AddPromptHandler extends AbstractAuthenticationRequestParameterValueMessageHandler<Prompt> {
+
+    /** Class logger. */
+    @Nonnull
+    private final Logger log = LoggerFactory.getLogger(AddPromptHandler.class);
+
+    /** Constructor.*/
+    public AddPromptHandler() {
+        super(Prompt.class);
+    }
+
+    @Override
+    protected void doInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException {
+
+        final Prompt prompt = getParameterValue(messageContext);
+        if (prompt != null) {
+            if (log.isTraceEnabled()) {
+                log.trace("{} Setting 'prompt={}'", getLogPrefix(), prompt.toString());
+            }            
+            getAuthenticationRequest().setPrompt(prompt);            
+        }
+    }
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddRedirectURIHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddRedirectURIHandler.java
new file mode 100644
index 0000000..f7a073f
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddRedirectURIHandler.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.request.impl;
+
+import java.net.URI;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.slf4j.Logger;
+
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.oidc.profile.impl.AbstractAuthenticationRequestParameterValueMessageHandler;
+
+/** 
+ * A message handler that adds a redirect_uri to the authentication request.
+ */
+public class AddRedirectURIHandler extends AbstractAuthenticationRequestParameterValueMessageHandler<URI> {
+
+    /** Logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(AddRedirectURIHandler.class);
+//    
+//    /** Function to create a suitable redirect URI from the given servlet request and profile request context.*/
+//    @NonnullAfterInit private BiFunction<HttpServletRequest, ProfileRequestContext, URI> redirectUriCreationStrategy;
+    
+    /** Constructor.*/
+    public AddRedirectURIHandler() {
+        super(URI.class);
+    }
+
+    @Override protected void doInvoke(@Nonnull final MessageContext messageContext) 
+            throws MessageHandlerException {   
+       
+        final URI redirectUri = getParameterValue(messageContext);
+        if (redirectUri == null) {
+            throw new MessageHandlerException("Redirect URI could not be located or created using the strategy");
+        }
+        log.trace("{} Created redirect_uri '{}'", getLogPrefix(), redirectUri);
+        getAuthenticationRequest().setRedirectURI(redirectUri);
+  
+    }
+
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddRequestedClaimsHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddRequestedClaimsHandler.java
similarity index 94%
rename from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddRequestedClaimsHandler.java
rename to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddRequestedClaimsHandler.java
index 9cd6a3e..312da18 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddRequestedClaimsHandler.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddRequestedClaimsHandler.java
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.sp.oidc.messaging.impl;
+package net.shibboleth.sp.oidc.profile.request.impl;
 
 import java.util.function.Function;
 
@@ -28,6 +28,7 @@ import com.nimbusds.openid.connect.sdk.OIDCClaimsRequest;
 
 import net.shibboleth.shared.logic.FunctionSupport;
 import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.oidc.profile.impl.AbstractOIDCAuthenticationRequestActionMessageHandlerNOPE;
 
 
 
@@ -39,7 +40,7 @@ import net.shibboleth.shared.primitive.LoggerFactory;
  * <p>Also records in the request whether the upstream OP supports the claims parameter, for later inspection by 
  * downstream components that only has access to the request e.g. an encoder.</p>
  */
-public class AddRequestedClaimsHandler extends AbstractOIDCAuthenticationRequestActionMessageHandler {
+public class AddRequestedClaimsHandler extends AbstractOIDCAuthenticationRequestActionMessageHandlerNOPE {
     
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(AddRequestedClaimsHandler.class);
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddResponseModeHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddResponseModeHandler.java
new file mode 100644
index 0000000..f0dfc3a
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddResponseModeHandler.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.request.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.slf4j.Logger;
+
+import com.nimbusds.oauth2.sdk.ResponseMode;
+
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.oidc.profile.impl.AbstractAuthenticationRequestParameterValueMessageHandler;
+
+/**
+ * A message handler that populates the authentication request response_type.
+ */
+public class AddResponseModeHandler extends AbstractAuthenticationRequestParameterValueMessageHandler<ResponseMode> {
+
+    /** Logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(AddResponseModeHandler.class);
+    
+    /** Constructor.*/
+    public AddResponseModeHandler() {
+        super(ResponseMode.class);
+    }    
+    
+    @Override protected void doInvoke(@Nonnull final MessageContext messageContext) 
+                throws MessageHandlerException {
+        
+        final ResponseMode responseModeFromLookup = getParameterValue(messageContext);
+        
+        log.trace("{} response mode configured as '{}'",getLogPrefix(), responseModeFromLookup);
+        
+        final ResponseMode compatibleMode = ResponseMode.resolve(null, getAuthenticationRequest().getResponseType());
+        if (compatibleMode == null) {
+            throw new MessageHandlerException("A compatible response_mode for response_type "
+                    + "'"+getAuthenticationRequest().getResponseType()+"' could not be found");
+        }
+        
+        checkProviderSupportsResponseMode(compatibleMode);
+        
+        log.trace("{} Compatible response_mode '{}' resolved from response_type '{}'", getLogPrefix(), compatibleMode, 
+                getAuthenticationRequest().getResponseType());
+        
+        if (responseModeFromLookup != null && !responseModeFromLookup.equals(compatibleMode)) {
+            log.debug("{} response_mode override '{}' exists from configuration and is different than the"
+                    + " default mode '{}' for response_type '{}'",
+                    getLogPrefix(), responseModeFromLookup, compatibleMode, 
+                    getAuthenticationRequest().getResponseType());  
+            
+            checkProviderSupportsResponseMode(responseModeFromLookup);
+            getAuthenticationRequest().setResponseMode(responseModeFromLookup);
+            
+        } else {
+            getAuthenticationRequest().setResponseMode(compatibleMode);
+        }
+
+        log.trace("{} response_mode '{}' selected", getLogPrefix(), getAuthenticationRequest().getResponseMode());
+    }
+    
+    /**
+     * Check the OpenID Provider supports the response_mode from its metadata value response_modes_supported. Throws
+     * an exception if not.
+     * 
+     * @param responseMode the response_mode to check is supported
+     * 
+     * @throws MessageHandlerException if the OpenID Provider does not support the response_mode
+     */
+    private void checkProviderSupportsResponseMode(@Nonnull final ResponseMode responseMode) 
+            throws MessageHandlerException {
+        final List<ResponseMode> responseModesSupportedOP = getProviderMetadata().getResponseModes();
+        final List<ResponseMode> responseModesSupported = new ArrayList<>(2);
+        if (responseModesSupportedOP == null || responseModesSupportedOP.isEmpty()) {
+            // Add the defaults from the specification
+            responseModesSupported.add(ResponseMode.QUERY);
+            responseModesSupported.add(ResponseMode.FRAGMENT);
+        } else {
+            responseModesSupportedOP.forEach(responseModesSupported::add);
+        }
+        if (!responseModesSupported.contains(responseMode)) {
+            throw new MessageHandlerException("OpenID Provider does not support chosen response_mode: "
+                    + responseMode.toString());
+        }
+        
+    }
+
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddResponseTypeHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddResponseTypeHandler.java
new file mode 100644
index 0000000..2e54188
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddResponseTypeHandler.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc.profile.request.impl;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.slf4j.Logger;
+
+import com.nimbusds.oauth2.sdk.ResponseMode;
+import com.nimbusds.oauth2.sdk.ResponseType;
+
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.oidc.profile.impl.AbstractAuthenticationRequestParameterValueMessageHandler;
+
+/**
+ * A message handler that populates the authentication request response_type.
+ */
+public class AddResponseTypeHandler extends AbstractAuthenticationRequestParameterValueMessageHandler<ResponseType> {
+
+    /** Logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(AddResponseTypeHandler.class);
+    
+    /** Constructor.*/
+    public AddResponseTypeHandler() {
+        super(ResponseType.class);
+    }    
+    
+    @Override protected void doInvoke(@Nonnull final MessageContext messageContext) 
+                throws MessageHandlerException {
+        
+        final ResponseType responseType = getParameterValue(messageContext);
+        if (responseType == null){
+            throw new MessageHandlerException("response_type '"+responseType+"' is not supported");
+        }        
+        checkProviderSupportsResponseType(responseType);         
+        
+        getAuthenticationRequest().setResponseType(responseType);
+        log.trace("{} response_type '{}' selected", getLogPrefix(), getAuthenticationRequest().getResponseType());
+    }
+    
+    /**
+     * Check the OpenID Provider supports the response_type from its metadata value response_types_supported. Throws
+     * an exception if not.
+     * 
+     * @param responseType the response_type to check is supported
+     * 
+     * @throws MessageHandlerException if the OpenID Provider does not support the response_type
+     */
+    private void checkProviderSupportsResponseType(@Nonnull final ResponseType responseType) 
+            throws MessageHandlerException {
+        final List<ResponseType> responseTypesSupported = getProviderMetadata().getResponseTypes();
+        if (responseTypesSupported == null) {
+            throw new MessageHandlerException("OpenID Provider has not specified supported response types "
+                    + "(response_types_supported). It MUST.");
+        }
+        if (!responseTypesSupported.contains(responseType)) {
+            throw new MessageHandlerException("OpenID Provider does not support chosen response_type: "
+                    + responseType.toString());
+        }
+    }
+
+    
+ // Checkstyle: ReturnCount OFF
+    /**
+     * Parse the response_mode into a known {@link ResponseMode}.
+     * 
+     * @param responseModeFromProfile the response_mode as a string
+     * 
+     * @return the parsed {@link ResponseMode}, or {@literal null} if the input type is unknown
+     */
+    @Nullable private ResponseMode parseResponseMode(@Nullable final String responseModeFromProfile) {
+        
+        if (responseModeFromProfile == null) {
+            return null;
+        }
+        
+        if (responseModeFromProfile.equals(ResponseMode.FORM_POST.getValue())) {
+            return ResponseMode.FORM_POST;
+        } else if (responseModeFromProfile.equals(ResponseMode.FORM_POST_JWT.getValue())) {
+            return ResponseMode.FORM_POST_JWT;
+        } else if (responseModeFromProfile.equals(ResponseMode.QUERY.getValue())) {
+            return ResponseMode.QUERY;
+        } else if (responseModeFromProfile.equals(ResponseMode.FRAGMENT.getValue())) {
+            return ResponseMode.FRAGMENT;
+        } else if (responseModeFromProfile.equals(ResponseMode.FRAGMENT_JWT.getValue())) {
+            return ResponseMode.FRAGMENT_JWT;
+        } else if (responseModeFromProfile.equals(ResponseMode.JWT.getValue())) {
+            return ResponseMode.JWT;
+        } else if (responseModeFromProfile.equals(ResponseMode.QUERY_JWT.getValue())) {
+            return ResponseMode.QUERY_JWT;
+        } else {
+            return null;
+        }
+    }
+ // Checkstyle: ReturnCount ON
+
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddScopesHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddScopesHandler.java
similarity index 72%
rename from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddScopesHandler.java
rename to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddScopesHandler.java
index 97794db..66d7fbd 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddScopesHandler.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddScopesHandler.java
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.sp.oidc.messaging.impl;
+package net.shibboleth.sp.oidc.profile.request.impl;
 
 import java.util.Set;
 
@@ -23,21 +23,28 @@ import org.opensaml.messaging.handler.MessageHandlerException;
 import org.slf4j.Logger;
 
 import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.oidc.profile.impl.AbstractAuthenticationRequestParameterValueMessageHandler;
 
 
 /** 
- * A message handler that adds the scopes from the profile request object to the authentication request.
+ * A message handler that adds OAuth 2.0 scopes to the authentication request.
  */
-public class AddScopesHandler extends AbstractOIDCAuthenticationRequestActionMessageHandler {
+public class AddScopesHandler extends AbstractAuthenticationRequestParameterValueMessageHandler<Set<String>> {
     
+    /**
+     * Constructor.
+     */
+    protected AddScopesHandler() {
+        super((Class)Set.class);
+    }
+
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(AddScopesHandler.class);
     
     @Override
     protected void doInvoke(@Nonnull final MessageContext messageContext) 
             throws MessageHandlerException {
-        
-        final Set<String> scopes = getProfileConfiguration().getScopes(lookupProfileRequestContext(messageContext));
+        final Set<String> scopes = getParameterValue(messageContext);
         if (scopes != null && !scopes.isEmpty()) {
             scopes.forEach(s -> getAuthenticationRequest().getScope().add(s));
         }
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddStateHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddStateHandler.java
similarity index 62%
rename from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddStateHandler.java
rename to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddStateHandler.java
index a9067a3..8b1e0cb 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/AddStateHandler.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddStateHandler.java
@@ -12,12 +12,9 @@
  * limitations under the License.
  */
 
-package net.shibboleth.sp.oidc.messaging.impl;
-
-import java.util.function.Function;
+package net.shibboleth.sp.oidc.profile.request.impl;
 
 import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
 
 import org.opensaml.messaging.context.MessageContext;
 import org.opensaml.messaging.handler.MessageHandlerException;
@@ -27,14 +24,22 @@ import com.nimbusds.oauth2.sdk.id.State;
 import com.nimbusds.openid.connect.sdk.claims.ClaimsSet;
 
 import net.shibboleth.shared.primitive.LoggerFactory;
-import net.shibboleth.sp.oidc.profile.impl.OIDCSupport;
+import net.shibboleth.sp.oidc.profile.impl.AbstractAuthenticationRequestParameterValueMessageHandler;
 
 /** 
- * Add state to the authentication request URL and the request object claims (if present).
- * By default this is generated by concatenating the Hex value of the spring webflow execution 
+ * Add an OAuth 2.0 / OpenID Connect {@code state} value to the authentication request URL and the request object 
+ * claims (if present). By default this is generated by concatenating the Hex value of the spring webflow execution 
  * key with a secure random 32 character nonce. 
- * */
-public class AddStateHandler extends AbstractOIDCAuthenticationRequestMessageHandler {
+ * 
+ *  * <p>
+ * The {@code state} parameter helps prevent cross-site request forgery
+ * (CSRF) attacks and can be used by clients to maintain request
+ * integrity.
+ * </p>
+ * 
+ */
+//TODO This need thinking about in the case of the RP-Full.
+public class AddStateHandler extends AbstractAuthenticationRequestParameterValueMessageHandler<String> {
     
     /** The 'state' claim name.*/
     @Nonnull private static final String STATE_CLAIM = "state";
@@ -42,35 +47,17 @@ public class AddStateHandler extends AbstractOIDCAuthenticationRequestMessageHan
     /** Logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(AddStateHandler.class);
     
-    /** Function to create a suitable 'state' to add to the authentication request.*/
-    @Nonnull private Function<MessageContext, String> stateGenerationStrategy;
     
     /** Constructor.*/
     public AddStateHandler() {
-        // By default, generate state a 32 character nonce.
-        stateGenerationStrategy = msg -> OIDCSupport.generateNonce(32);
-    }
-    
-    /**
-     * Set the creation strategy used to compute the 'state'.
-     * 
-     * @param strategy the creation strategy
-     */
-    public void setStateGenerationStrategy(
-            @Nullable final  Function<MessageContext, String> strategy) {
-    	checkSetterPreconditions();
-        
-        if (strategy != null) {
-            stateGenerationStrategy = strategy;
-        }
-        
+        super(String.class);
     }
 
     /** {@inheritDoc} */
     @Override
     protected void doInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException {
         
-        final String stateString = stateGenerationStrategy.apply(messageContext);        
+        final String stateString = getParameterValue(messageContext);        
         if (stateString == null) {
             throw new MessageHandlerException("Generated state was null");
         }
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/package-info.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/package-info.java
similarity index 80%
rename from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/package-info.java
rename to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/package-info.java
index 91d9f47..c6bfa07 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/messaging/impl/package-info.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/package-info.java
@@ -13,6 +13,6 @@
  */
 
 /**
- * Package that contains message handlers.
+ * Temporary OIDC profile implementation classes. These will be moved into oidc-common.
  */
-package net.shibboleth.sp.oidc.messaging.impl;
\ No newline at end of file
+package net.shibboleth.sp.oidc.profile.request.impl;
\ No newline at end of file

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


More information about the commits mailing list