[java-oidc-common] branch main updated: JCOMOIDC-21 - Move net.shibboleth.idp.plugin.oidc.op.config from oidc-op-impl into commons

Phil Smart philip.smart at jisc.ac.uk
Fri Nov 26 14:05:53 UTC 2021


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

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

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

The following commit(s) were added to refs/heads/main by this push:
     new aa7f1a1  JCOMOIDC-21 - Move net.shibboleth.idp.plugin.oidc.op.config from oidc-op-impl into commons
aa7f1a1 is described below

commit aa7f1a1f60ad722b33f27282676e4469ba76e432
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Fri Nov 26 14:05:46 2021 +0000

    JCOMOIDC-21 - Move net.shibboleth.idp.plugin.oidc.op.config from
    oidc-op-impl into commons
    
    - Added profile impl and api modules
    - Updated distribution and assembly.
    - Moved the core OIDC protocol config.
    - Moved the oauth2 config.
    - Had to move AuthnContextClassReference principal as well.
    
    https://shibboleth.atlassian.net/browse/JCOMOIDC-21
---
 .../src/main/assembly/plugin-assembly-tgz.xml      |  40 +
 .../src/main/assembly/plugin-assembly-zip.xml      |  40 +
 oidc-common-profile-api/pom.xml                    |  67 ++
 ...thenticationContextClassReferencePrincipal.java |  98 +++
 .../oidc/authn/principal/package-info.java         |  21 +
 ...IDCClientAuthenticableProfileConfiguration.java | 109 +++
 .../AbstractOIDCFlowAwareProfileConfiguration.java | 183 +++++
 .../config/OIDCCoreProtocolConfiguration.java      | 839 +++++++++++++++++++++
 .../profile/config/OIDCProfileConfiguration.java   |  27 +
 .../oidc/profile/config/package-info.java          |  21 +
 .../OAuth2TokenIntrospectionConfiguration.java     |  52 ++
 .../config/OAuth2TokenRevocationConfiguration.java |  53 ++
 .../oidc/profile/oauth2/config/package-info.java   |  21 +
 oidc-common-profile-impl/pom.xml                   |  52 ++
 pom.xml                                            |   2 +
 15 files changed, 1625 insertions(+)

diff --git a/oidc-common-dist/src/main/assembly/plugin-assembly-tgz.xml b/oidc-common-dist/src/main/assembly/plugin-assembly-tgz.xml
index 47cbe9a..9b7ce21 100644
--- a/oidc-common-dist/src/main/assembly/plugin-assembly-tgz.xml
+++ b/oidc-common-dist/src/main/assembly/plugin-assembly-tgz.xml
@@ -123,6 +123,46 @@
                 <include>*.jar</include>
             </includes>
         </fileSet>
+        
+        <!-- profile -->
+        <fileSet>
+            <directory>../oidc-common-profile-api/target</directory>
+            <outputDirectory>webapp/WEB-INF/lib</outputDirectory>
+            <includes>
+                <include>oidc-common-profile-api-*.jar</include>
+            </includes>
+            <excludes>
+                <exclude>*test*.jar</exclude>
+                <exclude>*javadoc.jar</exclude>
+                <exclude>*sources.jar</exclude>
+            </excludes>
+        </fileSet>
+        <fileSet>
+            <directory>../oidc-common-profile-api/target/dependency</directory>
+            <outputDirectory>webapp/WEB-INF/lib</outputDirectory>
+            <includes>
+                <include>*.jar</include>
+            </includes>
+        </fileSet>
+        <fileSet>
+            <directory>../oidc-common-profile-impl/target</directory>
+            <outputDirectory>webapp/WEB-INF/lib</outputDirectory>
+            <includes>
+                <include>oidc-common-profile-impl-*.jar</include>
+            </includes>
+            <excludes>
+                <exclude>*test*.jar</exclude>
+                <exclude>*javadoc.jar</exclude>
+                <exclude>*sources.jar</exclude>
+            </excludes>
+        </fileSet>
+        <fileSet>
+            <directory>../oidc-common-profile-impl/target/dependency</directory>
+            <outputDirectory>webapp/WEB-INF/lib</outputDirectory>
+            <includes>
+                <include>*.jar</include>
+            </includes>
+        </fileSet>
 
 		<!-- saml -->
 		<fileSet>
diff --git a/oidc-common-dist/src/main/assembly/plugin-assembly-zip.xml b/oidc-common-dist/src/main/assembly/plugin-assembly-zip.xml
index 9853d48..52c37c3 100644
--- a/oidc-common-dist/src/main/assembly/plugin-assembly-zip.xml
+++ b/oidc-common-dist/src/main/assembly/plugin-assembly-zip.xml
@@ -123,6 +123,46 @@
                 <include>*.jar</include>
             </includes>
         </fileSet>
+        
+         <!-- profile -->
+        <fileSet>
+            <directory>../oidc-common-profile-api/target</directory>
+            <outputDirectory>webapp/WEB-INF/lib</outputDirectory>
+            <includes>
+                <include>oidc-common-profile-api-*.jar</include>
+            </includes>
+            <excludes>
+                <exclude>*test*.jar</exclude>
+                <exclude>*javadoc.jar</exclude>
+                <exclude>*sources.jar</exclude>
+            </excludes>
+        </fileSet>
+        <fileSet>
+            <directory>../oidc-common-profile-api/target/dependency</directory>
+            <outputDirectory>webapp/WEB-INF/lib</outputDirectory>
+            <includes>
+                <include>*.jar</include>
+            </includes>
+        </fileSet>
+        <fileSet>
+            <directory>../oidc-common-profile-impl/target</directory>
+            <outputDirectory>webapp/WEB-INF/lib</outputDirectory>
+            <includes>
+                <include>oidc-common-profile-impl-*.jar</include>
+            </includes>
+            <excludes>
+                <exclude>*test*.jar</exclude>
+                <exclude>*javadoc.jar</exclude>
+                <exclude>*sources.jar</exclude>
+            </excludes>
+        </fileSet>
+        <fileSet>
+            <directory>../oidc-common-profile-impl/target/dependency</directory>
+            <outputDirectory>webapp/WEB-INF/lib</outputDirectory>
+            <includes>
+                <include>*.jar</include>
+            </includes>
+        </fileSet>
 
 		<!-- saml -->
 		<fileSet>
diff --git a/oidc-common-profile-api/pom.xml b/oidc-common-profile-api/pom.xml
new file mode 100644
index 0000000..a73230d
--- /dev/null
+++ b/oidc-common-profile-api/pom.xml
@@ -0,0 +1,67 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>net.shibboleth.oidc</groupId>
+        <artifactId>oidc-common-parent</artifactId>
+        <version>1.1.1-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>oidc-common-profile-api</artifactId>
+    <packaging>jar</packaging>
+    <name>Shibboleth IdP :: Plugins :: OIDC Common :: Profile Configuration API</name>
+    <description>Interfaces for common OIDC RP profile configuration functions/features.</description>
+
+    <properties>
+        <checkstyle.configLocation>${project.basedir}/../checkstyle.xml</checkstyle.configLocation>
+        <automatic.module.name>net.shibboleth.oidc.profile.api</automatic.module.name>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>net.shibboleth.idp</groupId>
+            <artifactId>idp-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>net.shibboleth.idp</groupId>
+            <artifactId>idp-profile-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>net.shibboleth.idp</groupId>
+            <artifactId>idp-authn-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.nimbusds</groupId>
+            <artifactId>oauth2-oidc-sdk</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-dependencies-test</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${project.target.directory}</outputDirectory>
+                            <includeScope>runtime</includeScope>
+                            <excludeTransitive>true</excludeTransitive>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/authn/principal/AuthenticationContextClassReferencePrincipal.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/authn/principal/AuthenticationContextClassReferencePrincipal.java
new file mode 100644
index 0000000..26962c7
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/authn/principal/AuthenticationContextClassReferencePrincipal.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.authn.principal;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.idp.authn.principal.CloneablePrincipal;
+import net.shibboleth.utilities.java.support.annotation.ParameterName;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+import com.google.common.base.MoreObjects;
+
+/** Principal based on a OIDC Authentication Context Class Reference. */
+public final class AuthenticationContextClassReferencePrincipal implements CloneablePrincipal {
+
+    /** unspecified auth ctx class. */
+    public static final String UNSPECIFIED = "net.shibboleth.idp.oidc.authn.principal.string.unspecified";
+
+    /** The class ref. */
+    @Nonnull
+    @NotEmpty
+    private String authnContextClassReference;
+
+    /**
+     * Constructor.
+     * 
+     * @param classRef the class reference URI
+     */
+    public AuthenticationContextClassReferencePrincipal(
+            @Nonnull @NotEmpty @ParameterName(name = "classRef") final String classRef) {
+        authnContextClassReference = Constraint.isNotNull(StringSupport.trimOrNull(classRef),
+                "AuthnContextClassRef cannot be null or empty");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    @Nonnull
+    @NotEmpty
+    public String getName() {
+        return authnContextClassReference;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return authnContextClassReference.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(final Object other) {
+        if (other == null) {
+            return false;
+        }
+
+        if (this == other) {
+            return true;
+        }
+
+        if (other instanceof AuthenticationContextClassReferencePrincipal) {
+            return authnContextClassReference.equals(((AuthenticationContextClassReferencePrincipal) other).getName());
+        }
+
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this).add("authnContextClassReference", authnContextClassReference)
+                .toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public AuthenticationContextClassReferencePrincipal clone() throws CloneNotSupportedException {
+        final AuthenticationContextClassReferencePrincipal copy =
+                (AuthenticationContextClassReferencePrincipal) super.clone();
+        copy.authnContextClassReference = authnContextClassReference;
+        return copy;
+    }
+}
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/authn/principal/package-info.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/authn/principal/package-info.java
new file mode 100644
index 0000000..fb924d8
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/authn/principal/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * OIDC-specific classes for integration with idp-authn-api packages.
+ */
+package net.shibboleth.oidc.authn.principal;
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/AbstractOIDCClientAuthenticableProfileConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/AbstractOIDCClientAuthenticableProfileConfiguration.java
new file mode 100644
index 0000000..88abf13
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/AbstractOIDCClientAuthenticableProfileConfiguration.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.profile.config;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
+
+import net.shibboleth.idp.profile.config.AbstractConditionalProfileConfiguration;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
+import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.logic.FunctionSupport;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+
+/**
+ * Base class for OIDC protocol configuration, containing configuration bit for setting client authentication methods.
+ */
+public abstract class AbstractOIDCClientAuthenticableProfileConfiguration
+        extends AbstractConditionalProfileConfiguration implements OIDCProfileConfiguration {
+
+    /** Enabled token endpoint authentication methods. */
+    @Nonnull private Function<ProfileRequestContext,Collection<String>> tokenEndpointAuthMethodsLookupStrategy;
+
+    /**
+     * Constructor.
+     *
+     * @param profileId Unique profile identifier
+     */
+    protected AbstractOIDCClientAuthenticableProfileConfiguration(@Nonnull @NotEmpty final String profileId) {
+        super(profileId);
+        
+        setTokenEndpointAuthMethods(
+                List.of(
+                        ClientAuthenticationMethod.CLIENT_SECRET_BASIC.toString(),
+                        ClientAuthenticationMethod.CLIENT_SECRET_POST.toString(),
+                        ClientAuthenticationMethod.CLIENT_SECRET_JWT.toString(),
+                        ClientAuthenticationMethod.PRIVATE_KEY_JWT.toString()));
+    }
+
+    /**
+     * Get the enabled token endpoint authentication methods.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return enabled token endpoint authentication methods
+     */
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getTokenEndpointAuthMethods(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        
+        final Collection<String> methods = tokenEndpointAuthMethodsLookupStrategy.apply(profileRequestContext);
+        if (methods != null) {
+            return List.copyOf(methods);
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * Set the enabled token endpoint authentication methods.
+     * 
+     * @param methods What to set.
+     */
+    public void setTokenEndpointAuthMethods(@Nonnull @NonnullElements final Collection<String> methods) {
+        Constraint.isNotNull(methods, "Collection of methods cannot be null");
+
+        if (methods != null) {
+            tokenEndpointAuthMethodsLookupStrategy =
+                    FunctionSupport.constant(List.copyOf(StringSupport.normalizeStringCollection(methods)));
+        } else {
+            tokenEndpointAuthMethodsLookupStrategy = FunctionSupport.constant(null);
+        }
+    }
+
+    /**
+     * Set a lookup strategy for the enabled token endpoint authentication methods.
+     *
+     * @param strategy  lookup strategy
+     */
+    public void setTokenEndpointAuthMethodsLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Collection<String>> strategy) {
+        tokenEndpointAuthMethodsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+}
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/AbstractOIDCFlowAwareProfileConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/AbstractOIDCFlowAwareProfileConfiguration.java
new file mode 100644
index 0000000..858f551
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/AbstractOIDCFlowAwareProfileConfiguration.java
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.profile.config;
+
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import com.google.common.base.Predicates;
+
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * Base class for OIDC protocol configuration, containing configuration bits shared by all flow aware OIDC protocol
+ * configurations.
+ */
+public abstract class AbstractOIDCFlowAwareProfileConfiguration
+        extends AbstractOIDCClientAuthenticableProfileConfiguration {
+
+    /** Predicate used to indicate whether authorization code flow is supported by this profile. Default true. */
+    @Nonnull private Predicate<ProfileRequestContext> authorizationCodeFlowPredicate;
+
+    /** Predicate used to indicate whether implicit flow is supported by this profile. Default true. */
+    @Nonnull private Predicate<ProfileRequestContext> implicitFlowPredicate;
+
+    /** Predicate used to indicate whether hybrid flow is supported by this profile. Default true. */
+    @Nonnull private Predicate<ProfileRequestContext> hybridFlowPredicate;
+
+    /** Predicate used to indicate whether refresh tokens are supported by this profile. Default true. */
+    @Nonnull private Predicate<ProfileRequestContext> refreshTokensPredicate;
+
+    /**
+     * Constructor.
+     *
+     * @param profileId Unique profile identifier.
+     */
+    protected AbstractOIDCFlowAwareProfileConfiguration(final String profileId) {
+        super(profileId);
+        authorizationCodeFlowPredicate = Predicates.alwaysTrue();
+        implicitFlowPredicate = Predicates.alwaysTrue();
+        hybridFlowPredicate = Predicates.alwaysTrue();
+        refreshTokensPredicate = Predicates.alwaysTrue();
+    }
+
+    /**
+     * Get whether authorization code flow is supported by this profile.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return whether authorization code flow is supported by this profile
+     */
+    public boolean isAuthorizationCodeFlowEnabled(@Nullable final ProfileRequestContext profileRequestContext) {
+        return authorizationCodeFlowPredicate.test(profileRequestContext);
+    }
+
+    /**
+     * Set whether authorization code flow is supported by this profile.
+     * 
+     * @param flag flag to set
+     */
+    public void setAuthorizationCodeFlowEnabled(final boolean flag) {
+        authorizationCodeFlowPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+    }
+
+    /**
+     * Set condition used to indicate whether authorization code flow is supported by this profile.
+     * 
+     * @param condition condition to set
+     */
+    public void setAuthorizationCodeFlowEnabledPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        authorizationCodeFlowPredicate = Constraint.isNotNull(condition,
+                "Condition used to indicate whether authorization code flow is supported cannot be null");
+    }
+
+    /**
+     * Get whether implicit flow is supported by this profile.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return whether implicit flow is supported by this profile
+     */
+    public boolean isHybridFlowEnabled(@Nullable final ProfileRequestContext profileRequestContext) {
+        return hybridFlowPredicate.test(profileRequestContext);
+    }
+    
+    /**
+     * Set whether implicit flow is supported by this profile.
+     * 
+     * @param flag flag to set
+     */
+    public void setHybridFlowEnabled(final boolean flag) {
+        hybridFlowPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+    }
+
+    /**
+     * Set condition used to indicate whether implicit flow is supported by this profile.
+     * 
+     * @param condition condition to set
+     */
+    public void setHybridFlowEnabledPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        hybridFlowPredicate = Constraint.isNotNull(condition,
+                "Condition used to indicate whether implicit flow is supported cannot be null");
+    }
+
+    /**
+     * Get whether hybrid flow is supported by this profile.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return whether hybrid flow is supported by this profile
+     */
+    public boolean isImplicitFlowEnabled(@Nullable final ProfileRequestContext profileRequestContext) {
+        return implicitFlowPredicate.test(profileRequestContext);
+    }
+    
+    /**
+     * Set whether hybrid flow is supported by this profile.
+     * 
+     * @param flag flag to set
+     */
+    public void setImplicitFlowEnabled(final boolean flag) {
+        implicitFlowPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+    }
+
+    /**
+     * Set condition used to indicate whether hybrid flow is supported by this profile.
+     * 
+     * @param condition condition to set.
+     */
+    public void setImplicitFlowEnabledPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        implicitFlowPredicate = Constraint.isNotNull(condition,
+                "Condition used to indicate whether hybrid flow is supported cannot be null");
+    }
+
+    /**
+     * Get whether refresh tokens are supported by this profile.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return whether refresh tokens are supported by this profile
+     */
+    public boolean isRefreshTokensEnabled(@Nullable final ProfileRequestContext profileRequestContext) {
+        return refreshTokensPredicate.test(profileRequestContext);
+    }
+
+    /**
+     * Set whether refresh tokens are supported by this profile.
+     * 
+     * @param flag flag to set
+     */
+    public void setRefreshTokensEnabled(final boolean flag) {
+        refreshTokensPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+    }
+
+    /**
+     * Set condition used to indicate whether refresh tokens are supported by this profile.
+     * 
+     * @param condition condition to set
+     */
+    public void setRefreshTokensEnabledPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        refreshTokensPredicate = Constraint.isNotNull(condition,
+                "Condition used to indicate whether refresh tokens are supported cannot be null");
+    }
+
+}
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCCoreProtocolConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCCoreProtocolConfiguration.java
new file mode 100644
index 0000000..253df3b
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCCoreProtocolConfiguration.java
@@ -0,0 +1,839 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.profile.config;
+
+import java.security.Principal;
+import java.time.Duration;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import com.google.common.base.Predicates;
+
+import net.shibboleth.idp.authn.config.AuthenticationProfileConfiguration;
+import net.shibboleth.idp.profile.config.OverriddenIssuerProfileConfiguration;
+import net.shibboleth.oidc.authn.principal.AuthenticationContextClassReferencePrincipal;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonNegative;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
+import net.shibboleth.utilities.java.support.annotation.constraint.Positive;
+import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.logic.FunctionSupport;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+
+/**
+ * Profile configuration for the OpenID Connect authorization and token endpoints.
+ */
+public class OIDCCoreProtocolConfiguration extends AbstractOIDCFlowAwareProfileConfiguration
+        implements AuthenticationProfileConfiguration, OverriddenIssuerProfileConfiguration {
+
+    /** OIDC base protocol URI. */
+    @Nonnull @NotEmpty public static final String PROTOCOL_URI = "http://openid.net/specs/openid-connect-core-1_0.html";
+
+    /** ID for this profile configuration. */
+    @Nonnull @NotEmpty public static final String PROFILE_ID = "http://shibboleth.net/ns/profiles/oidc/sso/browser";
+
+    /** Whether attributes should be resolved in the course of the profile. */
+    @Nonnull private Predicate<ProfileRequestContext> resolveAttributesPredicate;
+
+    /** Whether to mandate forced authentication for the request. */
+    @Nonnull private Predicate<ProfileRequestContext> forceAuthnPredicate;
+    
+    /** Whether all acr claim requests should be treated as Essential. */
+    @Nonnull private Predicate<ProfileRequestContext> acrRequestAlwaysEssentialPredicate;
+
+    /** Whether client is required to use PKCE. */
+    @Nonnull private Predicate<ProfileRequestContext> forcePKCEPredicate;
+
+    /** Whether client is allowed to use PKCE code challenge method plain. */
+    @Nonnull private Predicate<ProfileRequestContext> allowPKCEPlainPredicate;
+
+    /** Whether to encode consent in authorization code and access/refresh tokens. */
+    @Nonnull private Predicate<ProfileRequestContext> encodeConsentInTokensPredicate;
+
+    /** Lookup function to override issuer value. */
+    @Nonnull private Function<ProfileRequestContext,String> issuerLookupStrategy;
+    
+    /** Lookup function to supply proxyCount property. */
+    @Nonnull private Function<ProfileRequestContext,Integer> proxyCountLookupStrategy;
+
+    /** Lookup function to supply default authentication methods. */
+    @Nonnull private Function<ProfileRequestContext,Collection<AuthenticationContextClassReferencePrincipal>>
+            defaultAuthenticationContextsLookupStrategy;
+
+    /** Lookup function to supply authentication flows. */
+    @Nonnull private Function<ProfileRequestContext,Set<String>> authenticationFlowsLookupStrategy;
+
+    /** Lookup function to supply post authentication flows. */
+    @Nonnull private Function<ProfileRequestContext,Collection<String>> postAuthenticationFlowsLookupStrategy;
+
+    /** Lookup function to supply ID token lifetime. */
+    @Nonnull private Function<ProfileRequestContext,Duration> idTokenLifetimeLookupStrategy;
+
+    /** Lookup function to supply lifetime of authz code. */
+    @Nonnull private Function<ProfileRequestContext,Duration> authorizeCodeLifetimeLookupStrategy;
+
+    /** Lookup function to supply access token lifetime. */
+    @Nonnull private Function<ProfileRequestContext,Duration> accessTokenLifetimeLookupStrategy;
+
+    /** Lookup function to supply refresh token lifetime. */
+    @Nonnull private Function<ProfileRequestContext,Duration> refreshTokenLifetimeLookupStrategy;
+
+    /** Lookup function to supply additional audiences for ID token. */
+    @Nonnull private Function<ProfileRequestContext,Set<String>> assertionAudiencesLookupStrategy;
+    
+    /** Lookup function to supply attribute IDs to embed in authorization code or access token. */
+    @Nonnull private Function<ProfileRequestContext,Set<String>> encodedAttributesLookupStrategy;
+
+    /** Lookup function to supply attribute IDs to include in ID token regardless of response_type. */
+    @Nonnull private Function<ProfileRequestContext,Set<String>> alwaysIncludedAttributesLookupStrategy;
+
+    /** Lookup function to supply attribute IDs to omit from UserInfo token. */
+    @Nonnull private Function<ProfileRequestContext,Set<String>> deniedUserInfoAttributesLookupStrategy;
+
+    /**
+     * Constructor.
+     */
+    public OIDCCoreProtocolConfiguration() {
+        this(PROFILE_ID);
+    }
+
+    /**
+     * Creates a new configuration instance.
+     *
+     * @param profileId Unique profile identifier.
+     */
+    public OIDCCoreProtocolConfiguration(@Nonnull @NotEmpty final String profileId) {
+        super(profileId);
+        forceAuthnPredicate = Predicates.alwaysFalse();
+        resolveAttributesPredicate = Predicates.alwaysTrue();
+        issuerLookupStrategy = FunctionSupport.constant(null);
+        proxyCountLookupStrategy = FunctionSupport.constant(null);
+        assertionAudiencesLookupStrategy = FunctionSupport.constant(null);
+        
+        idTokenLifetimeLookupStrategy = FunctionSupport.constant(Duration.ofHours(1));
+        authorizeCodeLifetimeLookupStrategy = FunctionSupport.constant(Duration.ofMinutes(5));
+        accessTokenLifetimeLookupStrategy = FunctionSupport.constant(Duration.ofMinutes(10));
+        refreshTokenLifetimeLookupStrategy = FunctionSupport.constant(Duration.ofHours(2));
+        
+        acrRequestAlwaysEssentialPredicate = Predicates.alwaysFalse();
+        forcePKCEPredicate = Predicates.alwaysFalse();
+        allowPKCEPlainPredicate = Predicates.alwaysFalse();
+        encodeConsentInTokensPredicate = Predicates.alwaysFalse();
+        
+        defaultAuthenticationContextsLookupStrategy = FunctionSupport.constant(null);
+        authenticationFlowsLookupStrategy = FunctionSupport.constant(null);
+        postAuthenticationFlowsLookupStrategy = FunctionSupport.constant(null);
+        
+        encodedAttributesLookupStrategy = FunctionSupport.constant(null);
+        alwaysIncludedAttributesLookupStrategy = FunctionSupport.constant(null);
+        deniedUserInfoAttributesLookupStrategy = FunctionSupport.constant(null);
+    }
+    
+    /** {@inheritDoc} */
+    @Nullable @NotEmpty public String getIssuer(@Nullable final ProfileRequestContext profileRequestContext) {
+        return issuerLookupStrategy.apply(profileRequestContext);
+    }
+    
+    /**
+     * Set overridden issuer value.
+     * 
+     * @param issuer issuer value
+     */
+    public void setIssuer(@Nullable @NotEmpty final String issuer) {
+        issuerLookupStrategy = FunctionSupport.constant(issuer);
+    }
+    
+    /**
+     * Sets lookup strategy for overridden issuer value.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setIssuerLookupStrategy(@Nonnull final Function<ProfileRequestContext,String> strategy) {
+        issuerLookupStrategy = Constraint.isNotNull(strategy, "Issuer lookup strategy cannot be null");
+    }
+    
+    /**
+     * Get whether attributes should be resolved during the profile.
+     *
+     * <p>Default is true</p>
+     * 
+     * @param profileRequestContext current profile request context
+     * 
+     * @return true iff attributes should be resolved
+     */
+    public boolean isResolveAttributes(@Nullable final ProfileRequestContext profileRequestContext) {
+        return resolveAttributesPredicate.test(profileRequestContext);
+    }
+
+    /**
+     * Set whether attributes should be resolved during the profile.
+     * 
+     * @param flag flag to set
+     */
+    public void setResolveAttributes(final boolean flag) {
+        resolveAttributesPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+    }
+    
+    /**
+     * Set a condition to determine whether attributes should be resolved during the profile.
+     * 
+     * @param condition condition to set
+     */
+    public void setResolveAttributesPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        resolveAttributesPredicate = Constraint.isNotNull(condition, "Resolve attributes predicate cannot be null");
+    }
+    
+    /** {@inheritDoc} */
+    public boolean isForceAuthn(@Nullable final ProfileRequestContext profileRequestContext) {
+        return forceAuthnPredicate.test(profileRequestContext);
+    }
+    
+    /**
+     * Set whether a fresh user presence proof should be required for this request.
+     * 
+     * @param flag flag to set
+     */
+    public void setForceAuthn(final boolean flag) {
+        forceAuthnPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+    }
+    
+    /**
+     * Set a condition to determine whether a fresh user presence proof should be required for this request.
+     * 
+     * @param condition condition to set
+     */
+    public void setForceAuthnPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        forceAuthnPredicate = Constraint.isNotNull(condition, "Forced authentication predicate cannot be null");
+    }
+    
+    /** {@inheritDoc} */
+    @Nullable public Integer getProxyCount(@Nullable final ProfileRequestContext profileRequestContext) {
+        final Integer count = proxyCountLookupStrategy.apply(profileRequestContext);
+        if (count != null) {
+            Constraint.isGreaterThanOrEqual(0, count, "Proxy count must be greater than or equal to 0");
+        }
+        return count;
+    }
+
+    /**
+     * Sets the maximum number of times an assertion may be proxied outbound and/or
+     * the maximum number of hops between the relying party and a proxied authentication
+     * authority inbound.
+     * 
+     * @param count proxy count
+     */
+    public void setProxyCount(@Nullable @NonNegative final Integer count) {
+        if (count != null) {
+            Constraint.isGreaterThanOrEqual(0, count, "Proxy count must be greater than or equal to 0");
+        }
+        proxyCountLookupStrategy = FunctionSupport.constant(count);
+    }
+
+    /**
+     * Set a lookup strategy for the maximum number of times an assertion may be proxied outbound and/or
+     * the maximum number of hops between the relying party and a proxied authentication authority inbound.
+     *
+     * @param strategy  lookup strategy
+     */
+    public void setProxyCountLookupStrategy(@Nonnull final Function<ProfileRequestContext,Integer> strategy) {
+        proxyCountLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+    
+    /** {@inheritDoc} */
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public Set<String> getAuthenticationFlows(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        final Set<String> flows = authenticationFlowsLookupStrategy.apply(profileRequestContext);
+        if (flows != null) {
+            return Set.copyOf(flows);
+        }
+        return Collections.emptySet();
+    }
+
+    /**
+     * Set the authentication flows to use.
+     * 
+     * @param flows   flow identifiers to use
+     */
+    public void setAuthenticationFlows(@Nullable @NonnullElements final Collection<String> flows) {
+        if (flows != null) {
+            authenticationFlowsLookupStrategy =
+                    FunctionSupport.constant(Set.copyOf(StringSupport.normalizeStringCollection(flows)));
+        } else {
+            authenticationFlowsLookupStrategy = FunctionSupport.constant(null);
+        }
+    }
+
+    /**
+     * Set a lookup strategy for the authentication flows to use.
+     *
+     * @param strategy  lookup strategy
+     */
+    public void setAuthenticationFlowsLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+        authenticationFlowsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getPostAuthenticationFlows(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        final Collection<String> flows = postAuthenticationFlowsLookupStrategy.apply(profileRequestContext);
+        if (flows != null) {
+            return List.copyOf(flows);
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * Set the ordered collection of post-authentication interceptor flows to enable.
+     * 
+     * @param flows   flow identifiers to enable
+     */
+    public void setPostAuthenticationFlows(@Nullable @NonnullElements final Collection<String> flows) {
+        if (flows != null) {
+            postAuthenticationFlowsLookupStrategy =
+                    FunctionSupport.constant(List.copyOf(StringSupport.normalizeStringCollection(flows)));
+        } else {
+            postAuthenticationFlowsLookupStrategy = FunctionSupport.constant(null);
+        }
+    }
+
+    /**
+     * Set a lookup strategy for the post-authentication interceptor flows to enable.
+     *
+     * @param strategy  lookup strategy
+     */
+    public void setPostAuthenticationFlowsLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Collection<String>> strategy) {
+        postAuthenticationFlowsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public List<Principal> getDefaultAuthenticationMethods(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        final Collection<AuthenticationContextClassReferencePrincipal> methods =
+                defaultAuthenticationContextsLookupStrategy.apply(profileRequestContext);
+        if (methods != null) {
+            return List.copyOf(methods);
+        }
+        return Collections.emptyList();
+    }
+        
+    /**
+     * Set the default authentication contexts to use, expressed as custom principals.
+     * 
+     * @param contexts default authentication contexts to use
+     */
+    public void setDefaultAuthenticationMethods(
+            @Nullable @NonnullElements final Collection<AuthenticationContextClassReferencePrincipal> contexts) {
+        if (contexts != null) {
+            defaultAuthenticationContextsLookupStrategy = FunctionSupport.constant(List.copyOf(contexts));
+        } else {
+            defaultAuthenticationContextsLookupStrategy = FunctionSupport.constant(null);
+        }
+    }
+
+    /**
+     * Set a lookup strategy for the authentication contexts to use, expressed as custom principals.
+     *
+     * @param strategy  lookup strategy
+     */
+    public void setDefaultAuthenticationMethodsLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Collection<AuthenticationContextClassReferencePrincipal>>
+            strategy) {
+        defaultAuthenticationContextsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /**
+     * Get ID token lifetime.
+     * 
+     * <p>Defaults to 1 hour.</p>
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return ID token lifetime
+     */
+    @Positive @Nonnull public Duration getIDTokenLifetime(@Nullable final ProfileRequestContext profileRequestContext) {
+        
+        final Duration lifetime = idTokenLifetimeLookupStrategy.apply(profileRequestContext);
+        
+        Constraint.isTrue(lifetime != null && !lifetime.isZero() && !lifetime.isNegative(),
+                "ID token lifetime must be greater than 0");
+        return lifetime;
+    }
+
+    /**
+     * Set the lifetime of an id token.
+     * 
+     * @param lifetime lifetime of an id token in milliseconds
+     */
+    public void setIDTokenLifetime(@Positive @Nonnull final Duration lifetime) {
+        Constraint.isTrue(lifetime != null && !lifetime.isZero() && !lifetime.isNegative(),
+                "ID token lifetime must be greater than 0");
+        
+        idTokenLifetimeLookupStrategy = FunctionSupport.constant(lifetime);
+    }
+
+    /**
+     * Set a lookup strategy for the ID token lifetime.
+     *
+     * @param strategy lookup strategy
+     */
+    public void setIDTokenLifetimeLookupStrategy(@Nonnull final Function<ProfileRequestContext,Duration> strategy) {
+        idTokenLifetimeLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /**
+     * Get access token lifetime.
+     * 
+     * <p>Defaults to 10 minutes.</p>
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return access token lifetime
+     */
+    @Positive @Nonnull
+    public Duration getAccessTokenLifetime(@Nullable final ProfileRequestContext profileRequestContext) {
+        final Duration lifetime = accessTokenLifetimeLookupStrategy.apply(profileRequestContext);
+        
+        Constraint.isTrue(lifetime != null && !lifetime.isZero() && !lifetime.isNegative(),
+                "Access token lifetime must be greater than 0");
+        return lifetime;
+    }
+    
+    /**
+     * Set the lifetime of an access token.
+     * 
+     * @param lifetime lifetime of an access token in milliseconds
+     */
+    public void setAccessTokenLifetime(@Positive @Nonnull final Duration lifetime) {
+        Constraint.isTrue(lifetime != null && !lifetime.isZero() && !lifetime.isNegative(),
+                "Access token lifetime must be greater than 0");
+        
+        accessTokenLifetimeLookupStrategy = FunctionSupport.constant(lifetime);
+    }
+
+    
+    /**
+     * Set a lookup strategy for the access token lifetime.
+     *
+     * @param strategy lookup strategy
+     */
+    public void setAccessTokenLifetimeLookupStrategy(
+            @Nullable final Function<ProfileRequestContext,Duration> strategy) {
+        accessTokenLifetimeLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /**
+     * Get authz code lifetime.
+     * 
+     * <p>Defaults to 5 minutes.</p>
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return authz code lifetime
+     */
+    @Positive @Nonnull
+    public Duration getAuthorizeCodeLifetime(@Nullable final ProfileRequestContext profileRequestContext) {
+        final Duration lifetime = authorizeCodeLifetimeLookupStrategy.apply(profileRequestContext);
+        
+        Constraint.isTrue(lifetime != null && !lifetime.isZero() && !lifetime.isNegative(),
+                "Authorization code lifetime must be greater than 0");
+        return lifetime;
+    }
+
+    /**
+     * Set the lifetime of authz code.
+     * 
+     * @param lifetime lifetime of authz code
+     */
+    public void setAuthorizeCodeLifetime(@Positive @Nonnull final Duration lifetime) {
+        Constraint.isTrue(lifetime != null && !lifetime.isZero() && !lifetime.isNegative(),
+                "Authorization code lifetime must be greater than 0");
+        
+        authorizeCodeLifetimeLookupStrategy = FunctionSupport.constant(lifetime);
+    }
+    
+    /**
+     * Set a lookup strategy for the authz code lifetime.
+     *
+     * @param strategy lookup strategy
+     */
+    public void setAuthorizeCodeLifetimeLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Duration> strategy) {
+        authorizeCodeLifetimeLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /**
+     * Get refresh token lifetime.
+     * 
+     * <p>Defaults to 2 hours.</p>
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return refresh token lifetime
+     */
+    @Nonnull @Positive
+    public Duration getRefreshTokenLifetime(@Nullable final ProfileRequestContext profileRequestContext) {
+        
+        final Duration lifetime = refreshTokenLifetimeLookupStrategy.apply(profileRequestContext);
+        
+        Constraint.isTrue(lifetime != null && !lifetime.isZero() && !lifetime.isNegative(),
+                "Refresh token lifetime must be greater than 0");
+        return lifetime;
+    }
+
+    /**
+     * Set the lifetime of refresh token.
+     * 
+     * @param lifetime lifetime of an refresh token
+     */
+    public void setRefreshTokenLifetime(@Nonnull @Positive final Duration lifetime) {
+        Constraint.isTrue(lifetime != null && !lifetime.isZero() && !lifetime.isNegative(),
+                "Refresh token lifetime must be greater than 0");
+        
+        refreshTokenLifetimeLookupStrategy = FunctionSupport.constant(lifetime);
+    }
+
+    /**
+     * Set a lookup strategy for the refresh token lifetime.
+     *
+     * @param strategy lookup strategy
+     */
+    public void setRefreshTokenLifetimeLookupStrategy(
+            @Nullable final Function<ProfileRequestContext,Duration> strategy) {
+        refreshTokenLifetimeLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+    
+    /**
+     * Get the set of audiences, in addition to the relying party(ies) to which the IdP is issuing the ID Token, with
+     * which the token may be shared.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return the additional audiences
+     */
+    @Nonnull @NonnullElements @NotLive public Set<String> getAdditionalAudiencesForIdToken(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        
+        final Set<String> audiences = assertionAudiencesLookupStrategy.apply(profileRequestContext);
+        if (audiences != null) {
+            return Set.copyOf(audiences);
+        }
+        return Collections.emptySet();
+    }
+
+    /**
+     * Set the set of audiences, in addition to the relying party(ies) to which the IdP is issuing the ID Token, with
+     * which the token may be shared.
+     * 
+     * @param audiences the additional audiences
+     */
+    public void setAdditionalAudiencesForIdToken(@Nullable @NonnullElements final Collection<String> audiences) {
+
+        if (audiences == null || audiences.isEmpty()) {
+            assertionAudiencesLookupStrategy = FunctionSupport.constant(null);
+        } else {
+            assertionAudiencesLookupStrategy = FunctionSupport.constant(
+                    Set.copyOf(StringSupport.normalizeStringCollection(audiences)));
+        }
+    }
+
+    /**
+     * Set a lookup strategy for the set of audiences, in addition to the relying party(ies) to which the IdP
+     * is issuing the ID Token, with which the token may be shared.
+     *
+     * @param strategy  lookup strategy
+     */
+    public void setAdditionalAudiencesForIdTokenLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+        assertionAudiencesLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /**
+     * Get whether all acr claim requests should be treated as Essential.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return whether all acr claim requests should be treated as Essential
+     */
+    public boolean isAcrRequestAlwaysEssential(@Nullable final ProfileRequestContext profileRequestContext) {
+        return acrRequestAlwaysEssentialPredicate.test(profileRequestContext);
+    }
+
+    /**
+     * Set whether all acr claim requests should be treated as Essential.
+     * 
+     * @param flag flag to set
+     */
+    public void setAcrRequestAlwaysEssential(final boolean flag) {
+        acrRequestAlwaysEssentialPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+    }
+    
+    /**
+     * Set condition for whether all acr claim requests should be treated as Essential.
+     * 
+     * @param condition condition to set
+     */
+    public void setAcrRequestAlwaysEssentialPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        acrRequestAlwaysEssentialPredicate = Constraint.isNotNull(condition, "Condition cannot be null");
+    }
+
+    /**
+     * Get whether client is required to use PKCE.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return whether client is required to use PKCE
+     */
+    public boolean isForcePKCE(@Nullable final ProfileRequestContext profileRequestContext) {
+        return forcePKCEPredicate.test(profileRequestContext);
+    }
+
+    /**
+     * Set whether client is required to use PKCE.
+     * 
+     * @param flag flag to set
+     */
+    public void setForcePKCE(final boolean flag) {
+        forcePKCEPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+    }
+
+    /**
+     * Set condition for whether client is required to use PKCE.
+     * 
+     * @param condition condition to set
+     */
+    public void setForcePKCEPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        forcePKCEPredicate = Constraint.isNotNull(condition, "Condition cannot be null");
+    }
+
+    /**
+     * Get whether client is allowed to use PKCE code challenge method plain.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return whether client is allowed to use PKCE code challenge method plain
+     */
+    public boolean isAllowPKCEPlain(@Nullable final ProfileRequestContext profileRequestContext) {
+        return allowPKCEPlainPredicate.test(profileRequestContext);
+    }
+
+    /**
+     * Set whether client is allowed to use PKCE code challenge method plain.
+     * 
+     * @param flag flag to set
+     */
+    public void setAllowPKCEPlain(final boolean flag) {
+        allowPKCEPlainPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+    }
+
+    /**
+     * Set condition for whether client is allowed to use PKCE code challenge method plain.
+     * 
+     * @param condition condition to set
+     */
+    public void setAllowPKCEPlainPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        allowPKCEPlainPredicate = Constraint.isNotNull(condition, "Condition cannot be null");
+    }
+    
+
+    /**
+     * Get whether to encode consent in authorization code and access/refresh tokens.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return whether to encode consent in authorization code and access/refresh tokens
+     */
+    public boolean isEncodeConsentInTokens(@Nullable final ProfileRequestContext profileRequestContext) {
+        return encodeConsentInTokensPredicate.test(profileRequestContext);
+    }
+
+    /**
+     * Set whether to encode consent in authorization code and access/refresh tokens.
+     * 
+     * @param flag flag to set
+     */
+    public void setEncodeConsentInTokens(final boolean flag) {
+        encodeConsentInTokensPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+    }
+
+    /**
+     * Set condition for whether to encode consent in authorization code and access/refresh tokens.
+     * 
+     * @param condition condition to set
+     */
+    public void setEncodeConsentInTokensPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        encodeConsentInTokensPredicate = Constraint.isNotNull(condition, "Condition cannot be null");
+    }
+
+    /**
+     * Get the set of attribute IDs which should be encoded in encrypted form into the authorization code
+     * and/or access/refresh tokens to enable recovery on the back-channel.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return the attribute IDs to encode
+     */
+    @Nonnull @NonnullElements @NotLive public Set<String> getEncodedAttributes(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        
+        final Set<String> attributes = encodedAttributesLookupStrategy.apply(profileRequestContext);
+        if (attributes != null) {
+            return Set.copyOf(attributes);
+        }
+        return Collections.emptySet();
+    }
+
+    /**
+     * Set the set of attribute IDs which should be encoded in encrypted form into the authorization code
+     * and/or access/refresh tokens to enable recovery on the back-channel.
+     * 
+     * @param attributes the attribute IDs to encode
+     */
+    public void setEncodedAttributes(@Nullable @NonnullElements final Collection<String> attributes) {
+
+        if (attributes == null || attributes.isEmpty()) {
+            encodedAttributesLookupStrategy = FunctionSupport.constant(null);
+        } else {
+            encodedAttributesLookupStrategy = FunctionSupport.constant(
+                    Set.copyOf(StringSupport.normalizeStringCollection(attributes)));
+        }
+    }
+
+    /**
+     * Set a lookup strategy for the attribute IDs which should be encoded in encrypted form into the
+     * authorization code and/or access/refresh tokens to enable recovery on the back-channel.
+     *
+     * @param strategy  lookup strategy
+     */
+    public void setEncodedAttributesLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+        encodedAttributesLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /**
+     * Get the set of attribute IDs which should be included in the ID token regardless of response_type.
+     * 
+     * <p>Default behavior is to include claims only with the implicit id_token type only, while any use
+     * of a back-channel relies on the user_info endpoint to get the claims. This setting forces certain
+     * attributes to be added to the ID token regardless of flow.</p>
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return the attribute IDs to include in all cases
+     */
+    @Nonnull @NonnullElements @NotLive public Set<String> getAlwaysIncludedAttributes(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        
+        final Set<String> attributes = alwaysIncludedAttributesLookupStrategy.apply(profileRequestContext);
+        if (attributes != null) {
+            return Set.copyOf(attributes);
+        }
+        return Collections.emptySet();
+    }
+
+    /**
+     * Set the set of attribute IDs which should be included in the ID token regardless of response_type.
+     * 
+     * <p>Default behavior is to include claims only with the implicit id_token type only, while any use
+     * of a back-channel relies on the user_info endpoint to get the claims. This setting forces certain
+     * attributes to be added to the ID token regardless of flow.</p>
+     * 
+     * @param attributes the attribute IDs to include in all cases
+     */
+    public void setAlwaysIncludedAttributes(@Nullable @NonnullElements final Collection<String> attributes) {
+
+        if (attributes == null || attributes.isEmpty()) {
+            alwaysIncludedAttributesLookupStrategy = FunctionSupport.constant(null);
+        } else {
+            alwaysIncludedAttributesLookupStrategy = FunctionSupport.constant(
+                    Set.copyOf(StringSupport.normalizeStringCollection(attributes)));
+        }
+    }
+
+    /**
+     * Set a lookup strategy for the attribute IDs which should be included in the ID token regardless of
+     * response_type.
+     *
+     * @param strategy  lookup strategy
+     */
+    public void setAlwaysIncludedAttributesLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+        alwaysIncludedAttributesLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /**
+     * Get the set of attribute IDs which should be omitted from the UserInfo token.
+     * 
+     * <p>Default behavior is to include all claims, but omiited claims also affect the set that
+     * may need to be embedded for recovery into the access/refresh tokens.</p>
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return the attribute IDs to omit from UserInfo token
+     */
+    @Nonnull @NonnullElements @NotLive public Set<String> getDeniedUserInfoAttributes(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        
+        final Set<String> attributes = deniedUserInfoAttributesLookupStrategy.apply(profileRequestContext);
+        if (attributes != null) {
+            return Set.copyOf(attributes);
+        }
+        return Collections.emptySet();
+    }
+
+    /**
+     * Set the set of attribute IDs which should be omitted from the UserInfo token.
+     * 
+     * <p>Default behavior is to include all claims, but omiited claims also affect the set that
+     * may need to be embedded for recovery into the access/refresh tokens.</p>
+     * 
+     * @param attributes the attribute IDs to omit from UserInfo token
+     */
+    public void setDeniedUserInfoAttributes(@Nullable @NonnullElements final Collection<String> attributes) {
+
+        if (attributes == null || attributes.isEmpty()) {
+            deniedUserInfoAttributesLookupStrategy = FunctionSupport.constant(null);
+        } else {
+            deniedUserInfoAttributesLookupStrategy = FunctionSupport.constant(
+                    Set.copyOf(StringSupport.normalizeStringCollection(attributes)));
+        }
+    }
+
+    /**
+     * Set a lookup strategy for the set of attribute IDs which should be omitted from the UserInfo token.
+     *
+     * @param strategy  lookup strategy
+     */
+    public void setDeniedUserInfoAttributesLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+        deniedUserInfoAttributesLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+}
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCProfileConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCProfileConfiguration.java
new file mode 100644
index 0000000..b396dc9
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCProfileConfiguration.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.profile.config;
+
+import net.shibboleth.idp.profile.config.ProfileConfiguration;
+
+/**
+ * Marker interface for OIDC profile configurations.
+ */
+public interface OIDCProfileConfiguration extends ProfileConfiguration {
+
+}
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/package-info.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/package-info.java
new file mode 100644
index 0000000..1ff4ed1
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Profile configurations related to OIDC functionality.
+ */
+package net.shibboleth.oidc.profile.config;
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2TokenIntrospectionConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2TokenIntrospectionConfiguration.java
new file mode 100644
index 0000000..2ba5d8f
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2TokenIntrospectionConfiguration.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.profile.oauth2.config;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.oidc.profile.config.AbstractOIDCClientAuthenticableProfileConfiguration;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+
+/**
+ * Profile configuration for the OAuth2 Token Introspection.
+ */
+public class OAuth2TokenIntrospectionConfiguration extends AbstractOIDCClientAuthenticableProfileConfiguration {
+
+    /** OAuth2 Token Revocation URI. */
+    public static final String PROTOCOL_URI = "https://tools.ietf.org/html/rfc7662";
+
+    /** ID for this profile configuration. */
+    public static final String PROFILE_ID = "http://shibboleth.net/ns/profiles/oauth2/introspection";
+
+    /**
+     * Constructor.
+     */
+    public OAuth2TokenIntrospectionConfiguration() {
+        this(PROFILE_ID);
+    }
+
+    /**
+     * Creates a new configuration instance.
+     *
+     * @param profileId Unique profile identifier.
+     */
+    public OAuth2TokenIntrospectionConfiguration(@Nonnull @NotEmpty final String profileId) {
+        super(profileId);
+    }
+
+}
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2TokenRevocationConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2TokenRevocationConfiguration.java
new file mode 100644
index 0000000..0786ceb
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2TokenRevocationConfiguration.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.profile.oauth2.config;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.oidc.profile.config.AbstractOIDCClientAuthenticableProfileConfiguration;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+
+/**
+ * Profile configuration for the OAuth2 Token Revocation. The profile is required to define client authentication
+ * methods.
+ */
+public class OAuth2TokenRevocationConfiguration extends AbstractOIDCClientAuthenticableProfileConfiguration {
+
+    /** OAuth2 Token Revocation URI. */
+    public static final String PROTOCOL_URI = "https://tools.ietf.org/html/rfc7009";
+
+    /** ID for this profile configuration. */
+    public static final String PROFILE_ID = "http://shibboleth.net/ns/profiles/oauth2/revocation";
+
+    /**
+     * Constructor.
+     */
+    public OAuth2TokenRevocationConfiguration() {
+        this(PROFILE_ID);
+    }
+
+    /**
+     * Creates a new configuration instance.
+     *
+     * @param profileId Unique profile identifier.
+     */
+    public OAuth2TokenRevocationConfiguration(@Nonnull @NotEmpty final String profileId) {
+        super(profileId);
+    }
+
+}
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/package-info.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/package-info.java
new file mode 100644
index 0000000..8931423
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * OAuth2 profile configurations.
+ */
+package net.shibboleth.oidc.profile.oauth2.config;
\ No newline at end of file
diff --git a/oidc-common-profile-impl/pom.xml b/oidc-common-profile-impl/pom.xml
new file mode 100644
index 0000000..a0df674
--- /dev/null
+++ b/oidc-common-profile-impl/pom.xml
@@ -0,0 +1,52 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>net.shibboleth.oidc</groupId>
+        <artifactId>oidc-common-parent</artifactId>
+        <version>1.1.1-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>oidc-common-profile-impl</artifactId>
+    <packaging>jar</packaging>
+    <name>Shibboleth IdP :: Plugins :: OIDC Common :: Profile Configuration Implementation</name>
+    <description>Implementation for common OIDC RP profile configuration functions/features.</description>
+    
+    <properties>
+        <checkstyle.configLocation>${project.basedir}/../checkstyle.xml</checkstyle.configLocation>
+        <automatic.module.name>net.shibboleth.oidc.profile.impl</automatic.module.name>
+    </properties>
+    
+    <dependencies>
+        <dependency>
+            <groupId>net.shibboleth.idp</groupId>
+            <artifactId>idp-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-dependencies-test</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${project.target.directory}</outputDirectory>
+                            <includeScope>runtime</includeScope>
+                            <excludeTransitive>true</excludeTransitive>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index bba6bda..8458ca3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -209,6 +209,8 @@
         <module>oidc-common-plugin</module>
         <module>oidc-common-bom</module>
         <module>oidc-common-dist</module>
+        <module>oidc-common-profile-api</module>
+        <module>oidc-common-profile-impl</module>
     </modules>
     
     <build>

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


More information about the commits mailing list