Repository: gravitee-io/graviteeio-access-management
Pull request #929 (2020-10-05 15:20:53)

feat(franceconnect): Add initial support for France Connect social IDP
Closes gravitee-io/issues#4075


Patch:
diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/resources/handler/login/LoginSocialAuthenticationHandler.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/resources/handler/login/LoginSocialAuthenticationHandler.java
index 22a426f5fd..b902f8b90b 100644
--- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/resources/handler/login/LoginSocialAuthenticationHandler.java
+++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/java/io/gravitee/am/gateway/handler/root/resources/handler/login/LoginSocialAuthenticationHandler.java
@@ -49,7 +49,7 @@ import static io.gravitee.am.gateway.handler.common.vertx.utils.UriBuilderReques
 public class LoginSocialAuthenticationHandler implements Handler<RoutingContext> {
 
     private static final Logger logger = LoggerFactory.getLogger(LoginSocialAuthenticationHandler.class);
-    private static final List<String> socialProviders = Arrays.asList("github", "google", "twitter", "facebook", "bitbucket");
+    private static final List<String> socialProviders = Arrays.asList("github", "google", "twitter", "facebook", "bitbucket", "franceconnect");
     private static final String OAUTH2_PROVIDER_CONTEXT_KEY = "oauth2Providers";
     private static final String SOCIAL_PROVIDER_CONTEXT_KEY = "socialProviders";
     private static final String SOCIAL_AUTHORIZE_URL_CONTEXT_KEY = "authorizeUrls";
diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/resources/webroot/assets/css/login.css b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/resources/webroot/assets/css/login.css
index c91e423677..08accecce7 100644
--- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/resources/webroot/assets/css/login.css
+++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/resources/webroot/assets/css/login.css
@@ -273,3 +273,9 @@ a, a:hover, a:focus {
     color: #fff;
     background-color: #29a34e !important;;
 }
+
+.btn-franceconnect {
+    background: none;
+    box-shadow: none;
+    height: 70px;
+}
diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/resources/webroot/assets/images/FCboutons-10.svg b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/resources/webroot/assets/images/FCboutons-10.svg
new file mode 100644
index 0000000000..34d0505d7c
--- /dev/null
+++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/resources/webroot/assets/images/FCboutons-10.svg
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="283.5px" height="82.2px" viewBox="0 0 283.5 82.2" style="enable-background:new 0 0 283.5 82.2;" xml:space="preserve">
+<g>
+	<path style="fill:#1B1464;" d="M278,2H5.4C3,2,1.2,4,1.2,6.6v7.6c0,0,0,0,0,0v63.1c0,1.6,1,2.9,2.7,2.9h275.5
+		c1.7,0,2.8-1.3,2.8-2.9v-4.9c0,0,0,0,0,0V6.6C282.2,4,280.4,2,278,2z"/>
+	<path style="fill:#034EA2;" d="M49.1,3.4H5.5c-1.7,0-2.7,1.5-2.7,3.2v65.8c0,1.7,1,3,2.7,3h272.4c1.7,0,2.8-1.3,2.8-3V6.6
+		c0-1.7-1.1-3.2-2.8-3.2H49.1"/>
+	<g>
+		<path style="fill:#FFFFFF;" d="M102.7,34.4c-1,0.6-2.4,0.8-3.9,0.8c-1,0-2.4,0-3.8-0.2v-1.8c1.2,0.1,2.4,0.2,3.6,0.2
+			c1,0,2-0.1,2.6-0.4c0.8-0.3,1.2-1.1,1.2-2.1c0-1.3-0.6-1.9-1.9-2.3c-0.8-0.3-1.6-0.5-2.4-0.7c-2-0.6-3.2-1.7-3.2-3.9
+			c0-1.3,0.5-2.6,1.6-3.3c1.1-0.7,2.3-0.8,3.7-0.8c1,0,2.2,0.1,3.5,0.2v1.7c-1.2-0.1-2.4-0.2-3.3-0.2c-0.9,0-1.7,0-2.3,0.3
+			c-0.8,0.4-1.1,1.2-1.1,2c0,1.2,0.6,1.8,1.7,2.2c0.7,0.2,1.5,0.4,2.4,0.7c2.2,0.6,3.4,1.7,3.4,4.1
+			C104.4,32.2,103.9,33.6,102.7,34.4"/>
+		<path style="fill:#FFFFFF;" d="M106.5,25.3c0.8-2,1.4-3.8,1.9-5.7h2.1c-0.6,2.1-1.5,4.1-2.2,5.7H106.5z"/>
+		<path style="fill:#FFFFFF;" d="M113.3,19.5h2.1v2h-2.1V19.5z M115.2,34.9h-1.8V24.1h1.9L115.2,34.9L115.2,34.9z"/>
+		<path style="fill:#FFFFFF;" d="M126.4,34.9l-0.1-0.6c-1.2,0.4-2.5,0.9-3.8,0.9c-1.2,0-2.2-0.4-3-1.2c-1-1-1.4-2.5-1.4-4.5
+			c0-2.1,0.7-3.8,1.8-4.7c0.9-0.7,2.1-1,3.5-1c0.9,0,1.9,0.2,2.6,0.5v-4.7h1.9v15.3H126.4z M126.1,32.9v-7c-0.7-0.3-1.6-0.5-2.4-0.5
+			c-2.4,0-3.6,1.2-3.6,4.1c0,2.9,1.2,4.1,2.9,4.1C124.1,33.6,125.1,33.2,126.1,32.9"/>
+		<path style="fill:#FFFFFF;" d="M135.7,35.2c-1.2,0-2.5-0.3-3.4-1.2c-1-1.1-1.4-2.6-1.4-4.5c0-1.8,0.4-3.5,1.6-4.5
+			c0.9-0.7,1.9-1.1,3.4-1.1c1.2,0,2.4,0.3,3.3,1.1c1.3,1.1,1.4,2.8,1.4,5h-7.8c0.1,2.5,1.2,3.7,3.3,3.7c1.3,0,2.6-0.3,4.1-0.6v1.5
+			C138.8,34.8,137.2,35.2,135.7,35.2 M135.8,25.2c-2.1,0-2.8,1.3-2.9,3.4h5.8C138.6,26.3,137.8,25.2,135.8,25.2"/>
+		<path style="fill:#FFFFFF;" d="M151.2,34.9V28c0-1.9-1-2.6-2.6-2.6c-0.9,0-1.9,0.3-3.2,0.7v8.7h-1.9V24.1h1.6l0.1,0.6
+			c1.3-0.4,2.7-0.9,4-0.9c1.2,0,2.3,0.3,3.1,1.2c0.7,0.8,0.8,1.8,0.8,3v6.9H151.2z"/>
+		<path style="fill:#FFFFFF;" d="M160.2,35.2c-1.2,0-2.4-0.4-2.9-1.8c-0.3-0.8-0.4-1.8-0.4-2.9v-4.8h-1.8v-1.5h1.8l0.2-3.3h1.7v3.3
+			h3.2v1.5h-3.2v4.6c0,0.8,0,1.5,0.2,2.1c0.2,0.9,0.7,1.3,1.7,1.3c0.5,0,1.1-0.1,1.6-0.2v1.5C161.6,35,160.8,35.2,160.2,35.2"/>
+		<path style="fill:#FFFFFF;" d="M164.8,19.5h2.1v2h-2.1V19.5z M166.7,34.9h-1.8V24.1h1.9L166.7,34.9L166.7,34.9z"/>
+		<path style="fill:#FFFFFF;" d="M177.7,34.9v-9.2h-5v9.2h-1.9v-9.2H169v-1.5h1.8c0-1.6,0.3-2.9,1.3-3.8c0.9-0.8,2.2-1,4-1
+			c1,0,2,0.1,2.9,0.2V21c-0.9-0.1-1.9-0.2-2.9-0.2c-2.8,0-3.4,1-3.4,3.2h6.9v10.8H177.7z"/>
+		<path style="fill:#FFFFFF;" d="M187.3,35.2c-1.2,0-2.5-0.3-3.4-1.2c-1-1.1-1.4-2.6-1.4-4.5c0-1.8,0.4-3.5,1.6-4.5
+			c0.9-0.7,1.9-1.1,3.4-1.1c1.2,0,2.4,0.3,3.3,1.1c1.3,1.1,1.4,2.8,1.4,5h-7.8c0.1,2.5,1.2,3.7,3.3,3.7c1.3,0,2.6-0.3,4.1-0.6v1.5
+			C190.4,34.8,188.8,35.2,187.3,35.2 M187.4,25.2c-2.1,0-2.8,1.3-2.9,3.4h5.8C190.2,26.3,189.4,25.2,187.4,25.2"/>
+		<path style="fill:#FFFFFF;" d="M195.2,34.9V24.1h1.6l0.1,0.7c1.6-0.6,2.5-1,3.8-1h0.2v1.7h-0.4c-1.1,0-1.9,0.2-3.4,0.7v8.7H195.2z
+			"/>
+		<path style="fill:#FFFFFF;" d="M216.2,34.9l0-0.6c-1.4,0.4-2.6,0.9-3.9,0.9c-0.9,0-1.8-0.2-2.5-0.9c-0.7-0.6-1-1.4-1-2.5
+			c0-1.1,0.4-2.2,1.5-2.8c0.8-0.4,1.7-0.5,2.8-0.5c0.8,0,1.9,0.1,2.9,0.2v-0.5c0-2.1-0.9-2.8-3.3-2.8c-0.9,0-1.8,0.1-2.7,0.2V24
+			c1-0.1,2-0.2,3-0.2c1.4,0,2.9,0.1,3.8,1.1c0.9,0.9,1.1,2,1.1,3.6v6.5H216.2z M215.9,30c-0.9-0.1-2-0.1-2.8-0.1
+			c-1.9,0-2.6,0.7-2.6,1.9c0,1.1,0.8,1.9,2.2,1.9c1,0,2.1-0.3,3.2-0.7V30z"/>
+		<polygon style="fill:#FFFFFF;" points="223.8,34.9 219.6,24.1 221.7,24.1 224.9,33 225,33 228.2,24.1 230.2,24.1 226,34.9 		"/>
+		<path style="fill:#FFFFFF;" d="M236,35.2c-1.2,0-2.5-0.3-3.4-1.2c-1-1.1-1.4-2.6-1.4-4.5c0-1.8,0.4-3.5,1.6-4.5
+			c0.9-0.7,1.9-1.1,3.4-1.1c1.2,0,2.4,0.3,3.3,1.1c1.3,1.1,1.4,2.8,1.4,5h-7.8c0.1,2.5,1.2,3.7,3.3,3.7c1.3,0,2.6-0.3,4.1-0.6v1.5
+			C239.1,34.8,237.5,35.2,236,35.2 M236.1,25.2c-2.1,0-2.8,1.3-2.9,3.4h5.8C238.9,26.3,238.2,25.2,236.1,25.2"/>
+		<path style="fill:#FFFFFF;" d="M247.5,35.2c-1.1,0-2.3-0.3-3.1-1.2c-1-1.1-1.4-2.6-1.4-4.5c0-1.8,0.5-3.7,1.9-4.7
+			c1-0.8,2.3-1,3.6-1c0.8,0,1.6,0.1,2.6,0.2v1.6c-0.8-0.1-1.6-0.2-2.4-0.2c-2.6,0-3.6,1.3-3.6,4.1c0,2.5,1,4.1,3.1,4.1
+			c0.9,0,2.1-0.3,3.1-0.6v1.6C250,34.9,248.7,35.2,247.5,35.2"/>
+		<polygon style="fill:#FFFFFF;" points="98.2,52.4 98.2,58.2 95.7,58.2 95.7,43.6 105.2,43.6 105.2,45.6 98.2,45.6 98.2,50.4 
+			104.3,50.4 104.3,52.4 		"/>
+		<path style="fill:#FFFFFF;" d="M108.4,58.2V47.4h2l0.1,0.7c1.5-0.6,2.5-1,3.9-1h0.3v2.1H114c-1,0-1.9,0.2-3.3,0.7v8.4H108.4z"/>
+		<path style="fill:#FFFFFF;" d="M123.6,58.2l0-0.6c-1.4,0.5-2.6,0.9-4,0.9c-0.9,0-1.8-0.2-2.5-0.9c-0.7-0.6-1-1.4-1-2.5
+			c0-1.2,0.4-2.3,1.6-2.9c0.8-0.4,1.7-0.5,2.8-0.5c0.8,0,1.9,0,2.8,0.2v-0.4c0-1.9-0.7-2.5-3.1-2.5c-0.9,0-1.9,0.1-2.8,0.2v-1.8
+			c1-0.1,2.2-0.2,3.2-0.2c1.5,0,3,0.2,4,1c1,0.9,1.1,2.1,1.1,3.6v6.5H123.6z M123.3,53.4c-0.8-0.1-1.8-0.1-2.5-0.1
+			c-1.8,0-2.4,0.6-2.4,1.7c0,1,0.7,1.8,2,1.8c0.9,0,1.9-0.3,2.9-0.6V53.4z"/>
+		<path style="fill:#FFFFFF;" d="M137.5,58.2v-6.8c0-1.8-0.9-2.4-2.4-2.4c-0.8,0-1.8,0.2-2.9,0.7v8.5h-2.3V47.4h2l0.1,0.6
+			c1.4-0.4,2.7-0.9,4-0.9c1.2,0,2.3,0.3,3.1,1.2c0.7,0.8,0.9,1.8,0.9,3.1v6.8H137.5z"/>
+		<path style="fill:#FFFFFF;" d="M147.6,58.5c-1.1,0-2.3-0.3-3.2-1.2c-1-1-1.4-2.6-1.4-4.4c0-1.8,0.5-3.6,1.9-4.7c1-0.8,2.3-1,3.7-1
+			c0.8,0,1.7,0.1,2.7,0.2v1.9c-0.7-0.1-1.6-0.1-2.4-0.1c-2.4,0-3.4,1.2-3.4,3.8c0,2.3,0.9,3.8,2.9,3.8c0.9,0,2.1-0.3,3.1-0.6v1.8
+			C150.1,58.2,148.8,58.5,147.6,58.5"/>
+		<path style="fill:#FFFFFF;" d="M158.2,58.5c-1.2,0-2.5-0.3-3.5-1.2c-1-1-1.4-2.6-1.4-4.5c0-1.8,0.4-3.5,1.6-4.6
+			c0.9-0.8,2-1.1,3.5-1.1c1.2,0,2.5,0.3,3.4,1.1c1.3,1.2,1.5,2.8,1.5,5.1h-7.6c0,2.3,1.1,3.4,3.1,3.4c1.3,0,2.7-0.3,4.1-0.6v1.8
+			C161.5,58.1,159.8,58.5,158.2,58.5 M158.4,48.7c-1.9,0-2.5,1.2-2.6,3.1h5.3C161,49.7,160.3,48.7,158.4,48.7"/>
+		<path style="fill:#FFFFFF;" d="M172,58.5c-1.5,0-3.1-0.4-4.2-1.6c-1.4-1.4-1.9-3.5-1.9-6c0-2.4,0.7-4.8,2.5-6.3
+			c1.4-1.1,3.1-1.3,4.9-1.3c1.1,0,2.2,0.1,3.4,0.2v2.1c-1-0.1-2.2-0.2-3.2-0.2c-3.8,0-5.1,2.1-5.1,5.5c0,3.3,1.4,5.4,4.3,5.4
+			c1.3,0,2.9-0.4,4.2-0.8v2.1C175.3,58.1,173.6,58.5,172,58.5"/>
+		<path style="fill:#FFFFFF;" d="M181.1,57.4c-1.1-0.9-1.6-2.5-1.6-4.6s0.5-3.6,1.6-4.6c1-0.9,2.3-1.1,3.8-1.1
+			c1.4,0,2.7,0.3,3.8,1.1c1.1,0.9,1.6,2.5,1.6,4.5c0,2.1-0.5,3.6-1.6,4.6c-1,0.9-2.4,1.1-3.8,1.1C183.5,58.5,182.1,58.2,181.1,57.4
+			 M187.9,52.8c0-2.6-0.9-3.9-3-3.9c-2.2,0-3,1.2-3,3.8c0,2.6,0.9,4,3,4C187.1,56.7,187.9,55.5,187.9,52.8"/>
+		<path style="fill:#FFFFFF;" d="M201.3,58.2v-6.8c0-1.8-0.9-2.4-2.4-2.4c-0.8,0-1.8,0.2-2.9,0.7v8.5h-2.3V47.4h2l0.1,0.6
+			c1.4-0.4,2.7-0.9,4-0.9c1.2,0,2.3,0.3,3.1,1.2c0.7,0.8,0.9,1.8,0.9,3.1v6.8H201.3z"/>
+		<path style="fill:#FFFFFF;" d="M215.5,58.2v-6.8c0-1.8-0.9-2.4-2.4-2.4c-0.8,0-1.8,0.2-2.9,0.7v8.5h-2.3V47.4h2l0.1,0.6
+			c1.4-0.4,2.7-0.9,4-0.9c1.2,0,2.3,0.3,3.1,1.2c0.7,0.8,0.9,1.8,0.9,3.1v6.8H215.5z"/>
+		<path style="fill:#FFFFFF;" d="M225.8,58.5c-1.2,0-2.5-0.3-3.5-1.2c-1-1-1.4-2.6-1.4-4.5c0-1.8,0.4-3.5,1.6-4.6
+			c0.9-0.8,2-1.1,3.5-1.1c1.2,0,2.5,0.3,3.4,1.1c1.3,1.2,1.5,2.8,1.5,5.1h-7.6c0,2.3,1.1,3.4,3.1,3.4c1.3,0,2.7-0.3,4.1-0.6v1.8
+			C229.1,58.1,227.4,58.5,225.8,58.5 M226,48.7c-1.9,0-2.5,1.2-2.6,3.1h5.3C228.5,49.7,227.8,48.7,226,48.7"/>
+		<path style="fill:#FFFFFF;" d="M238.1,58.5c-1.1,0-2.3-0.3-3.2-1.2c-1-1-1.4-2.6-1.4-4.4c0-1.8,0.5-3.6,1.9-4.7c1-0.8,2.3-1,3.7-1
+			c0.8,0,1.7,0.1,2.7,0.2v1.9c-0.7-0.1-1.6-0.1-2.4-0.1c-2.4,0-3.4,1.2-3.4,3.8c0,2.3,0.9,3.8,2.9,3.8c0.9,0,2.1-0.3,3.1-0.6v1.8
+			C240.7,58.2,239.3,58.5,238.1,58.5"/>
+		<path style="fill:#FFFFFF;" d="M248.8,58.5c-1.2,0-2.3-0.4-2.9-1.7c-0.4-0.8-0.5-1.8-0.5-3v-4.6h-1.7v-1.8h1.7l0.3-3.3h2.1v3.3
+			h3.1v1.8h-3.1v4.2c0,0.8,0,1.5,0.2,2c0.2,0.8,0.7,1.1,1.6,1.1c0.5,0,1.1-0.1,1.6-0.2v1.8C250.3,58.3,249.5,58.5,248.8,58.5"/>
+	</g>
+	<g>
+		<polygon style="fill:#FFFFFF;" points="18,22 18,56.9 48.2,74.4 78.5,56.9 78.5,22 48.2,4.5 		"/>
+		<g>
+			<path style="fill:#1B1464;" d="M48.2,3.3L17,21.4v36.1l31.3,18l31.3-18V21.4L48.2,3.3z M78.5,56.9L48.2,74.4L18,56.9V22L48.2,4.5
+				L78.5,22V56.9z"/>
+		</g>
+		<polygon style="fill:#0069CC;" points="62.6,20.8 48.9,12.9 35.2,20.8 25.9,26.2 25.9,26.2 25.9,52.7 25.9,52.7 48.9,66 
+			71.9,52.7 71.9,52.7 71.9,26.2 71.9,26.2 		"/>
+		<g>
+			<polygon style="fill:#034EA2;" points="64.3,39.4 56,25.1 48.9,12.9 48.9,29.6 48.9,66 71.9,52.7 71.9,52.7 			"/>
+			<polygon style="fill:#0069CC;" points="56,25.1 64.3,39.4 71.9,26.2 71.9,26.2 62.6,20.8 			"/>
+			<polygon style="fill:#ED1C24;" points="62.6,20.8 48.9,12.9 56,25.1 			"/>
+			<polygon style="fill:#0069CC;" points="56,25.1 48.9,12.9 56,25.1 			"/>
+			<rect x="60.1" y="24" style="fill:#0069CC;" width="0" height="16.6"/>
+			<polygon style="fill:#ED1C24;" points="71.9,52.7 71.9,26.2 64.3,39.4 			"/>
+			<polygon style="fill:#ED1C24;" points="64.3,39.4 71.9,52.7 64.3,39.4 			"/>
+			<polygon style="fill:#0069CC;" points="33.6,39.4 41.9,25.1 48.9,12.9 48.9,29.6 48.9,66 25.9,52.7 25.9,52.7 			"/>
+			<polygon style="fill:#ED1C24;" points="41.9,25.1 33.6,39.4 25.9,26.2 25.9,26.2 35.2,20.8 			"/>
+			<polygon style="fill:#034EA2;" points="35.2,20.8 48.9,12.9 41.9,25.1 			"/>
+			<polygon style="fill:#0069CC;" points="41.9,25.1 48.9,12.9 41.9,25.1 			"/>
+			<rect x="37.7" y="24" style="fill:#0069CC;" width="0" height="16.6"/>
+			<polygon style="fill:#034EA2;" points="25.9,52.7 25.9,26.2 33.6,39.4 			"/>
+			<polygon style="fill:#0069CC;" points="33.6,39.4 25.9,52.7 33.6,39.4 			"/>
+		</g>
+		<g>
+			<path style="fill:#034EA2;" d="M57.4,42c0.4,0,0.8-0.1,1.2,0c0.3,0.1,0.7,0.1,0.7,0.2c-0.1,0.6-1,0.7-1.4,1.3c-0.1,0-0.1,0-0.2,0
+				c-0.2,0.1-0.1,0.5-0.3,0.5c-0.2-0.1-0.4,0-0.7,0.1c0.3,0.3,0.7,0.5,1.1,0.4c0.1,0,0.2,0.1,0.2,0.3c0,0,0.1,0,0.1-0.1
+				c0.1,0,0.1,0,0.1,0.1c0,0.1,0,0.2,0,0.3c-0.2,0.3-0.6,0.2-0.9,0.2c0.6,0.1,1.2,0.1,1.7,0c0.4-0.2,0-0.9,0.3-1.2
+				c-0.1,0,0-0.2-0.2-0.2c0.1-0.1,0.3-0.4,0.4-0.4c0.1,0,0.4-0.1,0.4-0.2c0-0.1-0.3-0.2-0.2-0.4c0.4-0.3,0.8-0.7,0.6-1.2
+				c-0.1-0.2-0.7-0.2-1-0.3c-0.4-0.1-0.8,0-1.2,0.1c-0.4,0-0.7,0.2-1.1,0.3c-0.5,0.2-0.9,0.5-1.4,0.8C56.3,42.3,56.8,42.2,57.4,42z"
+				/>
+			<path style="fill:#FFFFFF;" d="M63,46.4c-0.2-0.4-0.5-0.7-0.8-1.1c-0.3-0.5-0.7-0.9-0.8-1.5c-0.2-0.6,0-1.1,0-1.7
+				c0-1.1-0.3-2.2-0.6-3.2c-0.2-0.5-0.3-1.1-0.5-1.6c-0.1-0.3-0.2-0.6-0.4-0.9c-0.1-0.1-0.1-0.4,0-0.5c0.3-0.2,0.6-0.5,0.8-0.7
+				c0.2-0.4,0-0.9-0.3-1.1c-0.5-0.2-0.4,0.5-0.8,0.7c-0.1,0-0.1,0-0.2,0c-0.1-0.2,0.1-0.3,0.2-0.4c0-0.1,0-0.2-0.1-0.2
+				c-0.3,0-0.6-0.1-0.7-0.2c-0.8-1-1.8-1.5-2.9-1.9c0.3,0.1,0.6,0.1,0.9,0.1c0.5,0.1,1.1,0,1.5-0.2c0.4-0.2,0.4-0.7,0.5-1.1
+				c0.1-0.1,0-0.2,0-0.4c0-0.2-0.2-0.4-0.3-0.6c0,0-0.1-0.1-0.2-0.3c-0.8-0.9-3.9-3.5-9.7-3.1c-2.5,0.2-5.6,0.9-9.2,2.7
+				c-0.1,0-0.2,0.1-0.4,0.1c-0.6,0.3-1.4,0.8-1.9,1.4c-0.6,0.7-1.1,1.5-1.3,2.4c-0.9,0.6-1.5,1.5-2,2.4c-0.6,1.2-1.4,2.2-1.4,3.5
+				c0,0.1,0,0.2,0,0.2c0.1,0.4,0.1,0.7,0.2,1.1c0.2,0.8,0.4,1.6,0.5,2.4c0.1,0.4,0.2,0.8,0.3,1.2c0.2,0.4,0,0.9,0.3,1.3
+				c0.1,0.2,0.1,0.5,0.4,0.6c0,0.1,0,0.2,0,0.3c0.1,0.1,0.1,0.1,0.2,0.1c0,0.1,0,0.2,0,0.3c0.6,0.7,1.3,1.3,1.7,2.1
+				c0.2,0.4-0.7,0.2-1.1,0.1c-0.7-0.3-1.2-0.9-1.8-1.4c0,0-0.1,0.1-0.1,0.1c0.3,0.5,1.4,1.1,0.8,1.5c-0.3,0.2-0.7-0.2-0.9,0.1
+				c-0.1,0.1,0,0.3,0,0.4c-0.4-0.3-0.9-0.1-1.3-0.3c-0.3-0.1-0.4-0.6-0.7-0.6c-0.9-0.2-1.8-0.4-2.8-0.4c-0.1,0-0.2,0-0.2,0
+				c-0.9-0.1-1.8-0.2-2.6-0.1V49c0.8-0.2,1.6-0.4,2.4-0.4c0.1,0,0.2,0,0.2,0c0.2,0,0.5-0.1,0.7,0c-0.3,0-0.7,0-1,0.1
+				c-0.8,0.1-1.6,0.4-2.4,0.7v1c0.4,0.1,0.9,0.1,1.3,0.2c0.5,0.1,1,0.2,1.5,0.4c0.7,0.2,1.2,0.5,1.8,0.8c0.3,0.2,0.4,0.4,0.7,0.6
+				c0.4,0.2,0.9,0.2,1.2,0c0.1,0,0.3,0,0.4,0c1.1-0.3,2.2-0.6,2.9-1.5c0,0.1,0.1,0.1,0.1,0.1c-0.2,0.6-0.2,1.2-0.6,1.8
+				c0,0.1-0.1,0.2,0.1,0.3c0.1,0,0.1,0,0.1,0c-0.1,0-0.1,0-0.1,0.1c0,0.1,0.2,0,0.3,0.1c-0.4,0.1-0.7,0.2-0.9,0.5
+				c0,0.1,0.1,0.1,0.2,0.1c-0.1,0.1-0.4,0.1-0.4,0.2c0,0,0.1,0.1,0.1,0.1c-0.1,0-0.1,0-0.1,0.1c0,0.1,0,0.1,0,0.2
+				c-0.2,0-0.3,0.2-0.4,0.2c0.3,0.2,0.5,0,0.8,0c-0.8,0.3-1.4,0.8-2.2,1c-0.1,0,0,0.2-0.1,0.2c0.2,0.1,0.4-0.1,0.6-0.1
+				c-0.4,0.3-0.8,0.5-1.2,0.7l2.4,1.4c1-0.6,1.9-1.3,2.7-2.2c0,0,0.1,0.1,0.1,0.1c-0.2,0.7-0.6,1.2-1.2,1.7c-0.4,0.2-0.7,0.6-1,0.7
+				l1.8,1c0.4-0.3,0.7-0.5,1.2-0.7c0.1,0,0.2,0.1,0.4,0.1c0.6-0.6,1.3-1.3,2.3-1.1c0,0.1,0,0.1,0.1,0.1c0,0,0,0,0,0
+				c0,0,0.1,0,0.1-0.1c0,0.1,0,0.1-0.1,0.1c-0.3,0.2-0.5,0.4-0.8,0.6c-0.1,0.1,0,0.1,0.1,0.1c0.4-0.2,0.6-0.4,0.9-0.6
+				c-0.1,0.1-0.1,0.2-0.1,0.3c-0.9,0.7-1.6,1.4-2.3,2.2l9.5,5.5c0.3-0.4,0.7-1,1.1-1.5c1.8-2.6,4.4-6.1,5.2-6.9
+				c0.3-0.2,0.6-0.2,1-0.3c1.2,0,2.5,0.3,3.7,0.4c0.1,0,0.3,0.1,0.4,0.1c0.4,0.1,0.9,0,1.4-0.1c0.5-0.2,1.1-0.5,1.3-1.1
+				c0.2-0.5,0.3-1.1,0-1.6c-0.5-0.6,0.4-0.9,0.7-1.3c0.2-0.4-0.2-0.6-0.2-0.9c-0.1-0.1-0.4-0.1-0.5-0.3c0.5-0.2,1.3-0.7,0.9-1.3
+				c-0.2-0.4-0.6-0.9-0.2-1.3c0.5-0.3,1.3-0.3,1.5-0.8C64.3,47.8,63.4,47.1,63,46.4z M59.9,42.8c-0.1,0.1,0.2,0.2,0.2,0.4
+				c-0.1,0.1-0.3,0.2-0.4,0.2c-0.1,0.1-0.3,0.3-0.4,0.4c0.1,0,0,0.2,0.2,0.2c-0.3,0.4,0.2,1.1-0.3,1.2c-0.5,0.2-1.1,0.2-1.7,0
+				c0.3-0.1,0.7,0.1,0.9-0.2c0-0.1,0-0.2,0-0.3c0-0.1-0.1-0.1-0.1-0.1c-0.1,0.1-0.1,0.1-0.1,0.1c0-0.1-0.2-0.3-0.2-0.3
+				c-0.4,0.1-0.8-0.1-1.1-0.4c0.2-0.1,0.4-0.2,0.7-0.1c0.2,0,0.1-0.4,0.3-0.5c0.1,0,0.1,0,0.2,0c0.4-0.6,1.3-0.8,1.4-1.3
+				c0-0.1-0.4-0.1-0.7-0.2c-0.4-0.1-0.8,0-1.2,0c-0.6,0.2-1.1,0.2-1.6,0.5c0.4-0.3,0.9-0.6,1.4-0.8c0.4-0.1,0.7-0.3,1.1-0.3
+				c0.4-0.1,0.9-0.2,1.2-0.1c0.4,0.1,0.9,0.1,1,0.3C60.6,42.1,60.3,42.5,59.9,42.8z"/>
+		</g>
+	</g>
+</g>
+</svg>
diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/resources/webroot/views/login.html b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/resources/webroot/views/login.html
index 5ae620829c..acaaa36d98 100644
--- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/resources/webroot/views/login.html
+++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-core/src/main/resources/webroot/views/login.html
@@ -70,7 +70,10 @@
                         <a th:href="${authorizeUrls.get(socialProvider.getId())}"
                            th:class="'mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect btn-' + ${socialProvider.getType()}"
                            th:each="socialProvider : ${socialProviders}">
-                            <i th:class="'fa fa-' + ${socialProvider.getType()}"></i> <span th:text="${socialProvider.getName()}"></span>
+                            <img th:if="${socialProvider.getType()} == 'franceconnect'" th:src="@{assets/images/FCboutons-10.svg}" height="70">
+                            <span th:if="${socialProvider.getType()} != 'franceconnect'">
+                                <i th:class="'fa fa-' + ${socialProvider.getType()}"></i> <span th:text="${socialProvider.getName()}"></span>
+                            </span>
                         </a>
                     </div>
                 </div>
diff --git a/gravitee-am-gateway/gravitee-am-gateway-standalone/gravitee-am-gateway-standalone-distribution/pom.xml b/gravitee-am-gateway/gravitee-am-gateway-standalone/gravitee-am-gateway-standalone-distribution/pom.xml
index 9916148523..2853492734 100644
--- a/gravitee-am-gateway/gravitee-am-gateway-standalone/gravitee-am-gateway-standalone-distribution/pom.xml
+++ b/gravitee-am-gateway/gravitee-am-gateway-standalone/gravitee-am-gateway-standalone-distribution/pom.xml
@@ -121,6 +121,14 @@
             <scope>runtime</scope>
         </dependency>
 
+        <dependency>
+            <groupId>io.gravitee.am.identityprovider</groupId>
+            <artifactId>gravitee-am-identityprovider-franceconnect</artifactId>
+            <version>${project.version}</version>
+            <type>zip</type>
+            <scope>runtime</scope>
+        </dependency>
+
         <dependency>
             <groupId>io.gravitee.am.certificate</groupId>
             <artifactId>gravitee-am-certificate-javakeystore</artifactId>
@@ -328,6 +336,12 @@
                                     <version>${project.version}</version>
                                     <type>zip</type>
                                 </artifactItem>
+                                <artifactItem>
+                                    <groupId>io.gravitee.am.identityprovider</groupId>
+                                    <artifactId>gravitee-am-identityprovider-franceconnect</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>zip</type>
+                                </artifactItem>
 
                                 <!-- Certificates -->
                                 <artifactItem>
diff --git a/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/README.adoc b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/README.adoc
new file mode 100644
index 0000000000..1536c741c3
--- /dev/null
+++ b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/README.adoc
@@ -0,0 +1,13 @@
+
+
+
+# Setup FranceConnect IDP
+
+NOTE: Only for FranceConnect Dev environment
+
+Look at [FranceConnect](https://partenaires.franceconnect.gouv.fr/fcp/fournisseur-service)
+Your security domain must listen on /callback to make it work
+
+```
+> docker run --name proxy-france-connect -p 4242:4242 -v /path/to/graviteeio-access-management/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/nginx-franceconnect.conf:/etc/nginx/conf.d/default.conf:ro -d nginx
+```
\ No newline at end of file
diff --git a/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/nginx-franceconnect.conf b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/nginx-franceconnect.conf
new file mode 100644
index 0000000000..c8cd961bf5
--- /dev/null
+++ b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/nginx-franceconnect.conf
@@ -0,0 +1,19 @@
+upstream gio-gw {
+  server host.docker.internal:8092;
+}
+
+server {
+  listen 4242;
+  listen [::]:4242;
+
+  server_name _;
+
+  location /callback/ {
+    proxy_pass http://gio-gw/callback/login/callback;
+    proxy_redirect      default;
+    proxy_set_header    Host $host;
+    proxy_set_header    X-Real-IP $remote_addr;
+    proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
+    proxy_set_header    X-Forwarded-Host localhost:8092;
+  }
+}
\ No newline at end of file
diff --git a/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/pom.xml b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/pom.xml
new file mode 100644
index 0000000000..b7611b1edd
--- /dev/null
+++ b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/pom.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (C) 2015 The Gravitee team (http://gravitee.io)
+
+    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.
+
+-->
+<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>gravitee-am-identityprovider</artifactId>
+        <groupId>io.gravitee.am.identityprovider</groupId>
+        <version>3.3.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>gravitee-am-identityprovider-franceconnect</artifactId>
+
+    <version>3.3.0-SNAPSHOT</version>
+    <name>Gravitee IO - Access Management - Identity Provider - FranceConnect</name>
+
+    <dependencies>
+        <!-- Gravitee.io -->
+        <dependency>
+            <groupId>io.gravitee.am.identityprovider</groupId>
+            <artifactId>gravitee-am-identityprovider-common</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.gravitee.am.service</groupId>
+            <artifactId>gravitee-am-service</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- Spring -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- Jackson -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- Vert.x -->
+        <dependency>
+            <groupId>io.vertx</groupId>
+            <artifactId>vertx-rx-java2</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.vertx</groupId>
+            <artifactId>vertx-web-client</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- Test dependencies -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.github.tomakehurst</groupId>
+            <artifactId>wiremock</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <version>2.3</version>
+                <configuration>
+                    <appendAssemblyId>false</appendAssemblyId>
+                    <descriptors>
+                        <descriptor>src/main/assembly/plugin-assembly.xml</descriptor>
+                    </descriptors>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>make-plugin-assembly</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/assembly/plugin-assembly.xml b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/assembly/plugin-assembly.xml
new file mode 100644
index 0000000000..4de4108175
--- /dev/null
+++ b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/assembly/plugin-assembly.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>
+<!--
+
+    Copyright (C) 2015 The Gravitee team (http://gravitee.io)
+
+    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.
+
+-->
+<assembly>
+	<id>plugin</id>
+	<formats>
+		<format>zip</format>
+	</formats>
+	<includeBaseDirectory>false</includeBaseDirectory>
+
+	<!-- Include the main plugin Jar file -->
+	<files>
+		<file>
+			<source>${project.build.directory}/${project.build.finalName}.jar</source>
+		</file>
+	</files>
+
+	<fileSets>
+		<!-- Then include identity provider configuration schemas -->
+		<fileSet>
+			<directory>src/main/resources/schemas</directory>
+			<outputDirectory>schemas</outputDirectory>
+		</fileSet>
+
+		<!-- Create the empty lib directory in case of no libraries is required -->
+		<!-- As there is no maven-assembly-plugin's method do to that, we hack it ourself -->
+		<fileSet>
+			<directory>${project.basedir}/src/assembly</directory>
+			<outputDirectory>lib</outputDirectory>
+			<excludes>
+				<exclude>*</exclude>
+			</excludes>
+		</fileSet>
+	</fileSets>
+
+	<!-- Finally include plugin dependencies -->
+	<dependencySets>
+		<dependencySet>
+			<outputDirectory>lib</outputDirectory>
+			<useProjectArtifact>false</useProjectArtifact>
+		</dependencySet>
+	</dependencySets>
+</assembly>
\ No newline at end of file
diff --git a/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/java/io/gravitee/am/identityprovider/franceconnect/FranceConnectIdentityProvider.java b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/java/io/gravitee/am/identityprovider/franceconnect/FranceConnectIdentityProvider.java
new file mode 100644
index 0000000000..222c6ceca5
--- /dev/null
+++ b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/java/io/gravitee/am/identityprovider/franceconnect/FranceConnectIdentityProvider.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
+ *
+ * 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 io.gravitee.am.identityprovider.franceconnect;
+
+import io.gravitee.am.identityprovider.api.AuthenticationProvider;
+import io.gravitee.am.identityprovider.api.IdentityProviderConfiguration;
+import io.gravitee.am.identityprovider.api.social.SocialIdentityProvider;
+import io.gravitee.am.identityprovider.franceconnect.authentication.FranceConnectAuthenticationProvider;
+
+/**
+ * @author David BRASSELY (david.brassely at graviteesource.com)
+ * @author GraviteeSource Team
+ */
+public class FranceConnectIdentityProvider implements SocialIdentityProvider {
+
+    @Override
+    public Class<? extends IdentityProviderConfiguration> configuration() {
+        return FranceConnectIdentityProviderConfiguration.class;
+    }
+
+    @Override
+    public Class<? extends AuthenticationProvider> authenticationProvider() {
+        return FranceConnectAuthenticationProvider.class;
+    }
+}
diff --git a/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/java/io/gravitee/am/identityprovider/franceconnect/FranceConnectIdentityProviderConfiguration.java b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/java/io/gravitee/am/identityprovider/franceconnect/FranceConnectIdentityProviderConfiguration.java
new file mode 100644
index 0000000000..12a5a6c462
--- /dev/null
+++ b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/java/io/gravitee/am/identityprovider/franceconnect/FranceConnectIdentityProviderConfiguration.java
@@ -0,0 +1,132 @@
+/**
+ * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
+ *
+ * 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 io.gravitee.am.identityprovider.franceconnect;
+
+import io.gravitee.am.identityprovider.api.social.SocialIdentityProviderConfiguration;
+
+import java.util.Set;
+
+/**
+ * @author David BRASSELY (david.brassely at graviteesource.com)
+ * @author GraviteeSource Team
+ */
+public class FranceConnectIdentityProviderConfiguration implements SocialIdentityProviderConfiguration {
+
+    private String USER_AUTHORIZATION_URI = "/api/v1/authorize";
+    private String ACCESS_TOKEN_URI = "/api/v1/token";
+    private String USER_PROFILE_URI = "/api/v1/userinfo";
+    private String CODE_PARAMETER = "code";
+    private String RESPONSE_TYPE = "code";
+    private String clientId;
+    private String clientSecret;
+    private Set<String> scopes;
+    private Integer connectTimeout = 10000;
+    private Integer maxPoolSize = 100;
+    private Environment environment = Environment.INTEGRATION;
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public String getClientSecret() {
+        return clientSecret;
+    }
+
+    public void setClientSecret(String clientSecret) {
+        this.clientSecret = clientSecret;
+    }
+
+    public Set<String> getScopes() {
+        return scopes;
+    }
+
+    public void setScopes(Set<String> scopes) {
+        this.scopes = scopes;
+    }
+
+    public String getUserAuthorizationUri() {
+        return environment.url + USER_AUTHORIZATION_URI;
+    }
+
+    public String getAccessTokenUri() {
+        return environment.url + ACCESS_TOKEN_URI;
+    }
+
+    public String getUserProfileUri() {
+        return environment.url + USER_PROFILE_URI;
+    }
+
+    public String getCodeParameter() {
+        return CODE_PARAMETER;
+    }
+
+    public String getResponseType() {
+        return RESPONSE_TYPE;
+    }
+
+    public void setUserAuthorizationUri(String userAuthorizationUri) {
+        USER_AUTHORIZATION_URI = userAuthorizationUri;
+    }
+
+    public void setAccessTokenUri(String accessTokenUri) {
+        ACCESS_TOKEN_URI = accessTokenUri;
+    }
+
+    public void setUserProfileUri(String userProfileUri) {
+        USER_PROFILE_URI = userProfileUri;
+    }
+
+    public Integer getConnectTimeout() {
+        return connectTimeout;
+    }
+
+    public void setConnectTimeout(Integer connectTimeout) {
+        this.connectTimeout = connectTimeout;
+    }
+
+    public Integer getMaxPoolSize() {
+        return maxPoolSize;
+    }
+
+    public void setMaxPoolSize(Integer maxPoolSize) {
+        this.maxPoolSize = maxPoolSize;
+    }
+
+    public Environment getEnvironment() {
+        return environment;
+    }
+
+    public void setEnvironment(Environment environment) {
+        this.environment = environment;
+    }
+
+    public enum Environment {
+        TEST(""),
+        DEVELOPMENT("https://fcp.integ01.dev-franceconnect.fr"),
+        INTEGRATION("https://fcp.integ01.dev-franceconnect.fr"),
+        PRODUCTION("https://app.franceconnect.gouv.fr");
+
+        private String url;
+
+        Environment(String url) {
+            this.url = url;
+        }
+    }
+}
diff --git a/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/java/io/gravitee/am/identityprovider/franceconnect/authentication/FranceConnectAuthenticationProvider.java b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/java/io/gravitee/am/identityprovider/franceconnect/authentication/FranceConnectAuthenticationProvider.java
new file mode 100644
index 0000000000..e1aecb75bf
--- /dev/null
+++ b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/java/io/gravitee/am/identityprovider/franceconnect/authentication/FranceConnectAuthenticationProvider.java
@@ -0,0 +1,240 @@
+/**
+ * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
+ *
+ * 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 io.gravitee.am.identityprovider.franceconnect.authentication;
+
+import io.gravitee.am.common.exception.authentication.BadCredentialsException;
+import io.gravitee.am.common.oauth2.Parameters;
+import io.gravitee.am.common.oauth2.TokenTypeHint;
+import io.gravitee.am.common.oidc.StandardClaims;
+import io.gravitee.am.common.utils.SecureRandomString;
+import io.gravitee.am.common.web.UriBuilder;
+import io.gravitee.am.identityprovider.api.*;
+import io.gravitee.am.identityprovider.api.common.Request;
+import io.gravitee.am.identityprovider.common.oauth2.authentication.AbstractSocialAuthenticationProvider;
+import io.gravitee.am.identityprovider.common.oauth2.utils.URLEncodedUtils;
+import io.gravitee.am.identityprovider.franceconnect.FranceConnectIdentityProviderConfiguration;
+import io.gravitee.am.identityprovider.franceconnect.authentication.spring.FranceConnectAuthenticationProviderConfiguration;
+import io.gravitee.am.identityprovider.franceconnect.model.FranceConnectUser;
+import io.gravitee.am.model.http.BasicNameValuePair;
+import io.gravitee.am.model.http.NameValuePair;
+import io.gravitee.common.http.HttpHeaders;
+import io.gravitee.common.http.HttpMethod;
+import io.gravitee.common.http.MediaType;
+import io.netty.handler.codec.http.QueryStringDecoder;
+import io.reactivex.Maybe;
+import io.vertx.core.json.JsonObject;
+import io.vertx.reactivex.core.buffer.Buffer;
+import io.vertx.reactivex.ext.web.client.WebClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Import;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static io.gravitee.am.common.oidc.Scope.SCOPE_DELIMITER;
+
+/**
+ * @author David BRASSELY (david.brassely at graviteesource.com)
+ * @author GraviteeSource Team
+ */
+@Import(FranceConnectAuthenticationProviderConfiguration.class)
+public class FranceConnectAuthenticationProvider extends AbstractSocialAuthenticationProvider<FranceConnectIdentityProviderConfiguration> {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(FranceConnectAuthenticationProvider.class);
+    private static final String CLIENT_ID = "client_id";
+    private static final String CLIENT_SECRET = "client_secret";
+    private static final String REDIRECT_URI = "redirect_uri";
+    private static final String CODE = "code";
+    private static final String ACCESS_TOKEN_PARAMETER = "access_token";
+
+    @Autowired
+    @Qualifier("franceConnectWebClient")
+    private WebClient client;
+
+    @Autowired
+    private FranceConnectIdentityProviderConfiguration configuration;
+
+    @Autowired
+    private DefaultIdentityProviderMapper mapper;
+
+    @Autowired
+    private DefaultIdentityProviderRoleMapper roleMapper;
+
+    @Override
+    protected FranceConnectIdentityProviderConfiguration getConfiguration() {
+        return this.configuration;
+    }
+
+    @Override
+    protected IdentityProviderMapper getIdentityProviderMapper() {
+        return this.mapper;
+    }
+
+    @Override
+    protected IdentityProviderRoleMapper getIdentityProviderRoleMapper() {
+        return this.roleMapper;
+    }
+
+    @Override
+    protected WebClient getClient() {
+        return this.client;
+    }
+
+    @Override
+    public Request signInUrl(String redirectUri) {
+        try {
+            UriBuilder builder = UriBuilder.fromHttpUrl(getConfiguration().getUserAuthorizationUri());
+            builder.addParameter(Parameters.CLIENT_ID, getConfiguration().getClientId());
+            if (getConfiguration().getEnvironment() == FranceConnectIdentityProviderConfiguration.Environment.DEVELOPMENT) {
+                // NOTE: Port is being proxied by nginx. Please have a look to the README.adoc file
+                QueryStringDecoder decoder = new QueryStringDecoder(redirectUri);
+                builder.addParameter(Parameters.REDIRECT_URI, "http://localhost:4242/callback?provider=" + decoder.parameters().get("provider").get(0));
+            } else {
+                builder.addParameter(Parameters.REDIRECT_URI, redirectUri);
+            }
+            builder.addParameter(Parameters.RESPONSE_TYPE, getConfiguration().getResponseType());
+            builder.addParameter(io.gravitee.am.common.oidc.Parameters.NONCE, SecureRandomString.generate());
+            builder.addParameter(Parameters.STATE, SecureRandomString.generate());
+
+            if (getConfiguration().getScopes() != null && !getConfiguration().getScopes().isEmpty()) {
+                builder.addParameter(Parameters.SCOPE, String.join(SCOPE_DELIMITER, getConfiguration().getScopes()));
+            }
+
+            Request request = new Request();
+            request.setMethod(HttpMethod.GET);
+            request.setUri(builder.build().toString());
+            return request;
+        } catch (Exception e) {
+            LOGGER.error("An error occurs while building Sign In URL", e);
+            return null;
+        }
+    }
+
+    @Override
+    protected Maybe<Token> authenticate(Authentication authentication) {
+        // prepare body request parameters
+        final String authorizationCode = authentication.getContext().request().parameters().getFirst(configuration.getCodeParameter());
+        if (authorizationCode == null || authorizationCode.isEmpty()) {
+            LOGGER.debug("Authorization code is missing, skip authentication");
+            return Maybe.error(new BadCredentialsException("Missing authorization code"));
+        }
+        List<NameValuePair> urlParameters = new ArrayList<>();
+        urlParameters.add(new BasicNameValuePair(CLIENT_ID, configuration.getClientId()));
+        urlParameters.add(new BasicNameValuePair(CLIENT_SECRET, configuration.getClientSecret()));
+        urlParameters.add(new BasicNameValuePair(Parameters.GRANT_TYPE, "authorization_code"));
+        if (getConfiguration().getEnvironment() == FranceConnectIdentityProviderConfiguration.Environment.DEVELOPMENT) {
+            // NOTE: Port is being proxied by nginx. Please have a look to the README.adoc file
+            QueryStringDecoder decoder = new QueryStringDecoder((String) authentication.getContext().get(REDIRECT_URI));
+            urlParameters.add(new BasicNameValuePair(Parameters.REDIRECT_URI, "http://localhost:4242/callback?provider=" + decoder.parameters().get("provider").get(0)));
+        } else {
+            urlParameters.add(new BasicNameValuePair(Parameters.REDIRECT_URI, (String) authentication.getContext().get(REDIRECT_URI)));
+        }
+        urlParameters.add(new BasicNameValuePair(CODE, authorizationCode));
+        String bodyRequest = URLEncodedUtils.format(urlParameters);
+
+        return client.postAbs(configuration.getAccessTokenUri())
+                .putHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(bodyRequest.length()))
+                .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED)
+                .rxSendBuffer(Buffer.buffer(bodyRequest))
+                .toMaybe()
+                .map(httpResponse -> {
+                    if (httpResponse.statusCode() != 200) {
+                        throw new BadCredentialsException(httpResponse.statusMessage());
+                    }
+
+                    JsonObject response = httpResponse.bodyAsJsonObject();
+                    String accessToken = response.getString(ACCESS_TOKEN_PARAMETER);
+                    return new Token(accessToken, TokenTypeHint.ACCESS_TOKEN);
+                });
+    }
+
+    @Override
+    protected Maybe<User> profile(Token accessToken, Authentication authentication) {
+        return client.getAbs(configuration.getUserProfileUri())
+                .putHeader(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken.getValue())
+                .rxSend()
+                .toMaybe()
+                .map(httpClientResponse -> {
+                    if (httpClientResponse.statusCode() != 200) {
+                        throw new BadCredentialsException(httpClientResponse.statusMessage());
+                    }
+
+                    return createUser(httpClientResponse.bodyAsJsonObject().getMap());
+                });
+    }
+
+    private User createUser(Map<String, Object> attributes) {
+        String username = (String) attributes.getOrDefault(StandardClaims.PREFERRED_USERNAME, attributes.get(StandardClaims.SUB));
+
+        // Looks like the preferred_username can be empty
+        if (username == null || username.isEmpty()) {
+            username = (String) attributes.get(StandardClaims.SUB);
+        }
+
+        User user = new DefaultUser(username);
+        ((DefaultUser) user).setId(String.valueOf(attributes.get(StandardClaims.SUB)));
+
+        if (attributes.get(StandardClaims.EMAIL) != null) {
+            String email = (String) attributes.get(StandardClaims.EMAIL);
+            if (email != null && !email.isEmpty()) {
+                ((DefaultUser) user).setEmail(email);
+            }
+        }
+
+        // set additional information
+        Map<String, Object> additionalInformation = new HashMap<>();
+
+        // Standard claims
+        additionalInformation.put(StandardClaims.SUB, attributes.get(StandardClaims.SUB));
+        additionalInformation.put(StandardClaims.NAME, attributes.get(StandardClaims.NAME));
+        additionalInformation.put(StandardClaims.PREFERRED_USERNAME, attributes.get(StandardClaims.PREFERRED_USERNAME));
+
+        // apply user mapping
+        additionalInformation.putAll(applyUserMapping(attributes));
+
+        // update username if user mapping has been changed
+        if (additionalInformation.containsKey(StandardClaims.PREFERRED_USERNAME)) {
+            ((DefaultUser) user).setUsername((String) additionalInformation.get(StandardClaims.PREFERRED_USERNAME));
+        }
+        ((DefaultUser) user).setAdditionalInformation(additionalInformation);
+
+        // set user roles
+        ((DefaultUser) user).setRoles(applyRoleMapping(attributes));
+        return user;
+    }
+
+    protected Map<String, Object> defaultClaims(Map<String, Object> attributes) {
+        Map<String, Object> claims = new HashMap<>();
+
+        // Standard OIDC claims
+        claims.put(StandardClaims.GIVEN_NAME, attributes.get(StandardClaims.GIVEN_NAME));
+        claims.put(StandardClaims.FAMILY_NAME, attributes.get(StandardClaims.FAMILY_NAME));
+        claims.put(StandardClaims.EMAIL, attributes.get(StandardClaims.EMAIL));
+
+        // custom GitHub claims
+        claims.put(FranceConnectUser.BIRTH_DATE, attributes.get(FranceConnectUser.BIRTH_DATE));
+        claims.put(FranceConnectUser.BIRTH_PLACE, attributes.get(FranceConnectUser.BIRTH_PLACE));
+        claims.put(FranceConnectUser.BIRTH_COUNTRY, attributes.get(FranceConnectUser.BIRTH_COUNTRY));
+        claims.put(FranceConnectUser.GENDER, attributes.get(FranceConnectUser.GENDER));
+
+        return claims;
+    }
+}
diff --git a/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/java/io/gravitee/am/identityprovider/franceconnect/authentication/spring/FranceConnectAuthenticationProviderConfiguration.java b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/java/io/gravitee/am/identityprovider/franceconnect/authentication/spring/FranceConnectAuthenticationProviderConfiguration.java
new file mode 100644
index 0000000000..0c5452118f
--- /dev/null
+++ b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/java/io/gravitee/am/identityprovider/franceconnect/authentication/spring/FranceConnectAuthenticationProviderConfiguration.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
+ *
+ * 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 io.gravitee.am.identityprovider.franceconnect.authentication.spring;
+
+import io.gravitee.am.identityprovider.common.oauth2.utils.WebClientBuilder;
+import io.gravitee.am.identityprovider.franceconnect.FranceConnectIdentityProviderConfiguration;
+import io.vertx.reactivex.core.Vertx;
+import io.vertx.reactivex.ext.web.client.WebClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author David BRASSELY (david.brassely at graviteesource.com)
+ * @author GraviteeSource Team
+ */
+@Configuration
+public class FranceConnectAuthenticationProviderConfiguration {
+
+    @Autowired
+    private Vertx vertx;
+
+    @Autowired
+    private FranceConnectIdentityProviderConfiguration configuration;
+
+    @Bean
+    @Qualifier("franceConnectWebClient")
+    public WebClient httpClient() {
+        return WebClientBuilder.build(vertx, configuration);
+    }
+}
diff --git a/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/java/io/gravitee/am/identityprovider/franceconnect/model/FranceConnectUser.java b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/java/io/gravitee/am/identityprovider/franceconnect/model/FranceConnectUser.java
new file mode 100644
index 0000000000..b38b5b598f
--- /dev/null
+++ b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/java/io/gravitee/am/identityprovider/franceconnect/model/FranceConnectUser.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
+ *
+ * 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 io.gravitee.am.identityprovider.franceconnect.model;
+
+/**
+ * France Connect User claims
+ *
+ * See <a href="https://partenaires.franceconnect.gouv.fr/fcp/fournisseur-service>Fournisseur de Service Particulier</a>
+ *
+ * @author David BRASSELY (david.brassely at graviteesource.com)
+ * @author GraviteeSource Team
+ */
+public abstract class FranceConnectUser {
+
+    public static final String BIRTH_DATE = "birth_date";
+    public static final String GENDER = "gender";
+    public static final String BIRTH_PLACE = "birth_place";
+    public static final String BIRTH_COUNTRY = "birth_country";
+}
diff --git a/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/resources/plugin.properties b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/resources/plugin.properties
new file mode 100644
index 0000000000..d6dd00bc81
--- /dev/null
+++ b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/resources/plugin.properties
@@ -0,0 +1,6 @@
+id=franceconnect-am-idp
+name=${project.name}
+version=${project.version}
+description=${project.description}
+class=io.gravitee.am.identityprovider.franceconnect.FranceConnectIdentityProvider
+type=identity_provider
diff --git a/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/resources/schemas/schema-form.json b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/resources/schemas/schema-form.json
new file mode 100644
index 0000000000..c49de4e0fd
--- /dev/null
+++ b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/main/resources/schemas/schema-form.json
@@ -0,0 +1,77 @@
+{
+  "type" : "object",
+  "id" : "urn:jsonschema:io:gravitee:am:identityprovider:franceconnect:FranceConnectIdentityProviderConfiguration",
+  "description": "FranceConnect identity provider, let you register and set up permissions and authorization options for OAuth 2.0 protocol.\n\nhttps://partenaires.franceconnect.gouv.fr/ ",
+  "properties" : {
+    "environment" : {
+      "type": "string",
+      "enum": [
+        "DEVELOPMENT",
+        "INTEGRATION",
+        "PRODUCTION"
+      ],
+      "x-schema-form": {
+        "type": "select",
+        "titleMap": {
+          "DEVELOPMENT": "Dev - https://fcp.integ01.dev-franceconnect.fr",
+          "INTEGRATION": "Integration - https://fcp.integ01.dev-franceconnect.fr",
+          "PRODUCTION": "Production - https://app.franceconnect.gouv.fr"
+        }
+      },
+      "default": "PRODUCTION",
+      "title": "Environment",
+      "description": "FranceConnect is providing two environments (integration and production. development is provided for https://partenaires.franceconnect.gouv.fr/fcp/fournisseur-service)."
+    },
+    "clientId" : {
+      "type" : "string",
+      "title": "Client ID",
+      "description": "Required. The client ID you received from FranceConnect when you registered."
+    },
+    "clientSecret" : {
+      "type" : "string",
+      "title": "Client Secret",
+      "description": "Required. The client secret you received from FranceConnect for your FranceConnect App."
+    },
+    "scopes":{
+      "type": "array",
+      "title": "Scopes",
+      "description": "Scopes let you specify exactly what type of access you need. Scopes limit access for OAuth tokens.",
+      "items":
+        {
+          "type": "string",
+          "enum": [
+            "openid",
+            "profile",
+            "birth",
+            "identite_pivot",
+            "given_name",
+            "family_name",
+            "birthdate",
+            "gender",
+            "birthplace",
+            "birthcountry",
+            "email",
+            "preferred_username"]
+        }
+    },
+    "connectTimeout" : {
+      "type" : "integer",
+      "default": 10000,
+      "minimum": 1,
+      "title": "HTTP Client connect timeout",
+      "description": "Duration of time in milliseconds that connects will block. (default 10000 ms)"
+    },
+    "maxPoolSize" : {
+      "type" : "integer",
+      "default": 100,
+      "minimum": 1,
+      "title": "HTTP Client max pool size",
+      "description": "Maximum pool of connections can grow to. (default 100)"
+    }
+  },
+  "required": [
+    "environment",
+    "clientId",
+    "clientSecret"
+  ]
+}
diff --git a/gravitee-am-identityprovider/pom.xml b/gravitee-am-identityprovider/pom.xml
index 997c1b4d27..33a49c34c5 100644
--- a/gravitee-am-identityprovider/pom.xml
+++ b/gravitee-am-identityprovider/pom.xml
@@ -44,6 +44,7 @@
         <module>gravitee-am-identityprovider-azure-ad</module>
         <module>gravitee-am-identityprovider-facebook</module>
         <module>gravitee-am-identityprovider-twitter</module>
+        <module>gravitee-am-identityprovider-franceconnect</module>
     </modules>
 
     <dependencies>
diff --git a/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/java/io/gravitee/am/management/handlers/management/api/authentication/controller/LoginController.java b/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/java/io/gravitee/am/management/handlers/management/api/authentication/controller/LoginController.java
index db26695ecd..45f5e928c3 100644
--- a/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/java/io/gravitee/am/management/handlers/management/api/authentication/controller/LoginController.java
+++ b/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/java/io/gravitee/am/management/handlers/management/api/authentication/controller/LoginController.java
@@ -52,7 +52,7 @@ public class LoginController {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(LoginController.class);
     private static final String LOGIN_VIEW = "login";
-    private static final List<String> socialProviderTypes = Arrays.asList("github", "google", "twitter", "facebook", "bitbucket");
+    private static final List<String> socialProviderTypes = Arrays.asList("github", "google", "twitter", "facebook", "bitbucket", "franceconnect");
 
     @Autowired
     private OrganizationService organizationService;
diff --git a/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/resources/assets/css/login.css b/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/resources/assets/css/login.css
index 90d5392598..10942f4b2e 100644
--- a/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/resources/assets/css/login.css
+++ b/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/resources/assets/css/login.css
@@ -277,3 +277,9 @@ a, a:hover, a:focus {
     color: #fff;
     background-color: #29a34e !important;;
 }
+
+.btn-franceconnect {
+    background: none;
+    box-shadow: none;
+    height: 70px;
+}
diff --git a/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/resources/assets/images/FCboutons-10.svg b/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/resources/assets/images/FCboutons-10.svg
new file mode 100644
index 0000000000..34d0505d7c
--- /dev/null
+++ b/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/resources/assets/images/FCboutons-10.svg
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="283.5px" height="82.2px" viewBox="0 0 283.5 82.2" style="enable-background:new 0 0 283.5 82.2;" xml:space="preserve">
+<g>
+	<path style="fill:#1B1464;" d="M278,2H5.4C3,2,1.2,4,1.2,6.6v7.6c0,0,0,0,0,0v63.1c0,1.6,1,2.9,2.7,2.9h275.5
+		c1.7,0,2.8-1.3,2.8-2.9v-4.9c0,0,0,0,0,0V6.6C282.2,4,280.4,2,278,2z"/>
+	<path style="fill:#034EA2;" d="M49.1,3.4H5.5c-1.7,0-2.7,1.5-2.7,3.2v65.8c0,1.7,1,3,2.7,3h272.4c1.7,0,2.8-1.3,2.8-3V6.6
+		c0-1.7-1.1-3.2-2.8-3.2H49.1"/>
+	<g>
+		<path style="fill:#FFFFFF;" d="M102.7,34.4c-1,0.6-2.4,0.8-3.9,0.8c-1,0-2.4,0-3.8-0.2v-1.8c1.2,0.1,2.4,0.2,3.6,0.2
+			c1,0,2-0.1,2.6-0.4c0.8-0.3,1.2-1.1,1.2-2.1c0-1.3-0.6-1.9-1.9-2.3c-0.8-0.3-1.6-0.5-2.4-0.7c-2-0.6-3.2-1.7-3.2-3.9
+			c0-1.3,0.5-2.6,1.6-3.3c1.1-0.7,2.3-0.8,3.7-0.8c1,0,2.2,0.1,3.5,0.2v1.7c-1.2-0.1-2.4-0.2-3.3-0.2c-0.9,0-1.7,0-2.3,0.3
+			c-0.8,0.4-1.1,1.2-1.1,2c0,1.2,0.6,1.8,1.7,2.2c0.7,0.2,1.5,0.4,2.4,0.7c2.2,0.6,3.4,1.7,3.4,4.1
+			C104.4,32.2,103.9,33.6,102.7,34.4"/>
+		<path style="fill:#FFFFFF;" d="M106.5,25.3c0.8-2,1.4-3.8,1.9-5.7h2.1c-0.6,2.1-1.5,4.1-2.2,5.7H106.5z"/>
+		<path style="fill:#FFFFFF;" d="M113.3,19.5h2.1v2h-2.1V19.5z M115.2,34.9h-1.8V24.1h1.9L115.2,34.9L115.2,34.9z"/>
+		<path style="fill:#FFFFFF;" d="M126.4,34.9l-0.1-0.6c-1.2,0.4-2.5,0.9-3.8,0.9c-1.2,0-2.2-0.4-3-1.2c-1-1-1.4-2.5-1.4-4.5
+			c0-2.1,0.7-3.8,1.8-4.7c0.9-0.7,2.1-1,3.5-1c0.9,0,1.9,0.2,2.6,0.5v-4.7h1.9v15.3H126.4z M126.1,32.9v-7c-0.7-0.3-1.6-0.5-2.4-0.5
+			c-2.4,0-3.6,1.2-3.6,4.1c0,2.9,1.2,4.1,2.9,4.1C124.1,33.6,125.1,33.2,126.1,32.9"/>
+		<path style="fill:#FFFFFF;" d="M135.7,35.2c-1.2,0-2.5-0.3-3.4-1.2c-1-1.1-1.4-2.6-1.4-4.5c0-1.8,0.4-3.5,1.6-4.5
+			c0.9-0.7,1.9-1.1,3.4-1.1c1.2,0,2.4,0.3,3.3,1.1c1.3,1.1,1.4,2.8,1.4,5h-7.8c0.1,2.5,1.2,3.7,3.3,3.7c1.3,0,2.6-0.3,4.1-0.6v1.5
+			C138.8,34.8,137.2,35.2,135.7,35.2 M135.8,25.2c-2.1,0-2.8,1.3-2.9,3.4h5.8C138.6,26.3,137.8,25.2,135.8,25.2"/>
+		<path style="fill:#FFFFFF;" d="M151.2,34.9V28c0-1.9-1-2.6-2.6-2.6c-0.9,0-1.9,0.3-3.2,0.7v8.7h-1.9V24.1h1.6l0.1,0.6
+			c1.3-0.4,2.7-0.9,4-0.9c1.2,0,2.3,0.3,3.1,1.2c0.7,0.8,0.8,1.8,0.8,3v6.9H151.2z"/>
+		<path style="fill:#FFFFFF;" d="M160.2,35.2c-1.2,0-2.4-0.4-2.9-1.8c-0.3-0.8-0.4-1.8-0.4-2.9v-4.8h-1.8v-1.5h1.8l0.2-3.3h1.7v3.3
+			h3.2v1.5h-3.2v4.6c0,0.8,0,1.5,0.2,2.1c0.2,0.9,0.7,1.3,1.7,1.3c0.5,0,1.1-0.1,1.6-0.2v1.5C161.6,35,160.8,35.2,160.2,35.2"/>
+		<path style="fill:#FFFFFF;" d="M164.8,19.5h2.1v2h-2.1V19.5z M166.7,34.9h-1.8V24.1h1.9L166.7,34.9L166.7,34.9z"/>
+		<path style="fill:#FFFFFF;" d="M177.7,34.9v-9.2h-5v9.2h-1.9v-9.2H169v-1.5h1.8c0-1.6,0.3-2.9,1.3-3.8c0.9-0.8,2.2-1,4-1
+			c1,0,2,0.1,2.9,0.2V21c-0.9-0.1-1.9-0.2-2.9-0.2c-2.8,0-3.4,1-3.4,3.2h6.9v10.8H177.7z"/>
+		<path style="fill:#FFFFFF;" d="M187.3,35.2c-1.2,0-2.5-0.3-3.4-1.2c-1-1.1-1.4-2.6-1.4-4.5c0-1.8,0.4-3.5,1.6-4.5
+			c0.9-0.7,1.9-1.1,3.4-1.1c1.2,0,2.4,0.3,3.3,1.1c1.3,1.1,1.4,2.8,1.4,5h-7.8c0.1,2.5,1.2,3.7,3.3,3.7c1.3,0,2.6-0.3,4.1-0.6v1.5
+			C190.4,34.8,188.8,35.2,187.3,35.2 M187.4,25.2c-2.1,0-2.8,1.3-2.9,3.4h5.8C190.2,26.3,189.4,25.2,187.4,25.2"/>
+		<path style="fill:#FFFFFF;" d="M195.2,34.9V24.1h1.6l0.1,0.7c1.6-0.6,2.5-1,3.8-1h0.2v1.7h-0.4c-1.1,0-1.9,0.2-3.4,0.7v8.7H195.2z
+			"/>
+		<path style="fill:#FFFFFF;" d="M216.2,34.9l0-0.6c-1.4,0.4-2.6,0.9-3.9,0.9c-0.9,0-1.8-0.2-2.5-0.9c-0.7-0.6-1-1.4-1-2.5
+			c0-1.1,0.4-2.2,1.5-2.8c0.8-0.4,1.7-0.5,2.8-0.5c0.8,0,1.9,0.1,2.9,0.2v-0.5c0-2.1-0.9-2.8-3.3-2.8c-0.9,0-1.8,0.1-2.7,0.2V24
+			c1-0.1,2-0.2,3-0.2c1.4,0,2.9,0.1,3.8,1.1c0.9,0.9,1.1,2,1.1,3.6v6.5H216.2z M215.9,30c-0.9-0.1-2-0.1-2.8-0.1
+			c-1.9,0-2.6,0.7-2.6,1.9c0,1.1,0.8,1.9,2.2,1.9c1,0,2.1-0.3,3.2-0.7V30z"/>
+		<polygon style="fill:#FFFFFF;" points="223.8,34.9 219.6,24.1 221.7,24.1 224.9,33 225,33 228.2,24.1 230.2,24.1 226,34.9 		"/>
+		<path style="fill:#FFFFFF;" d="M236,35.2c-1.2,0-2.5-0.3-3.4-1.2c-1-1.1-1.4-2.6-1.4-4.5c0-1.8,0.4-3.5,1.6-4.5
+			c0.9-0.7,1.9-1.1,3.4-1.1c1.2,0,2.4,0.3,3.3,1.1c1.3,1.1,1.4,2.8,1.4,5h-7.8c0.1,2.5,1.2,3.7,3.3,3.7c1.3,0,2.6-0.3,4.1-0.6v1.5
+			C239.1,34.8,237.5,35.2,236,35.2 M236.1,25.2c-2.1,0-2.8,1.3-2.9,3.4h5.8C238.9,26.3,238.2,25.2,236.1,25.2"/>
+		<path style="fill:#FFFFFF;" d="M247.5,35.2c-1.1,0-2.3-0.3-3.1-1.2c-1-1.1-1.4-2.6-1.4-4.5c0-1.8,0.5-3.7,1.9-4.7
+			c1-0.8,2.3-1,3.6-1c0.8,0,1.6,0.1,2.6,0.2v1.6c-0.8-0.1-1.6-0.2-2.4-0.2c-2.6,0-3.6,1.3-3.6,4.1c0,2.5,1,4.1,3.1,4.1
+			c0.9,0,2.1-0.3,3.1-0.6v1.6C250,34.9,248.7,35.2,247.5,35.2"/>
+		<polygon style="fill:#FFFFFF;" points="98.2,52.4 98.2,58.2 95.7,58.2 95.7,43.6 105.2,43.6 105.2,45.6 98.2,45.6 98.2,50.4 
+			104.3,50.4 104.3,52.4 		"/>
+		<path style="fill:#FFFFFF;" d="M108.4,58.2V47.4h2l0.1,0.7c1.5-0.6,2.5-1,3.9-1h0.3v2.1H114c-1,0-1.9,0.2-3.3,0.7v8.4H108.4z"/>
+		<path style="fill:#FFFFFF;" d="M123.6,58.2l0-0.6c-1.4,0.5-2.6,0.9-4,0.9c-0.9,0-1.8-0.2-2.5-0.9c-0.7-0.6-1-1.4-1-2.5
+			c0-1.2,0.4-2.3,1.6-2.9c0.8-0.4,1.7-0.5,2.8-0.5c0.8,0,1.9,0,2.8,0.2v-0.4c0-1.9-0.7-2.5-3.1-2.5c-0.9,0-1.9,0.1-2.8,0.2v-1.8
+			c1-0.1,2.2-0.2,3.2-0.2c1.5,0,3,0.2,4,1c1,0.9,1.1,2.1,1.1,3.6v6.5H123.6z M123.3,53.4c-0.8-0.1-1.8-0.1-2.5-0.1
+			c-1.8,0-2.4,0.6-2.4,1.7c0,1,0.7,1.8,2,1.8c0.9,0,1.9-0.3,2.9-0.6V53.4z"/>
+		<path style="fill:#FFFFFF;" d="M137.5,58.2v-6.8c0-1.8-0.9-2.4-2.4-2.4c-0.8,0-1.8,0.2-2.9,0.7v8.5h-2.3V47.4h2l0.1,0.6
+			c1.4-0.4,2.7-0.9,4-0.9c1.2,0,2.3,0.3,3.1,1.2c0.7,0.8,0.9,1.8,0.9,3.1v6.8H137.5z"/>
+		<path style="fill:#FFFFFF;" d="M147.6,58.5c-1.1,0-2.3-0.3-3.2-1.2c-1-1-1.4-2.6-1.4-4.4c0-1.8,0.5-3.6,1.9-4.7c1-0.8,2.3-1,3.7-1
+			c0.8,0,1.7,0.1,2.7,0.2v1.9c-0.7-0.1-1.6-0.1-2.4-0.1c-2.4,0-3.4,1.2-3.4,3.8c0,2.3,0.9,3.8,2.9,3.8c0.9,0,2.1-0.3,3.1-0.6v1.8
+			C150.1,58.2,148.8,58.5,147.6,58.5"/>
+		<path style="fill:#FFFFFF;" d="M158.2,58.5c-1.2,0-2.5-0.3-3.5-1.2c-1-1-1.4-2.6-1.4-4.5c0-1.8,0.4-3.5,1.6-4.6
+			c0.9-0.8,2-1.1,3.5-1.1c1.2,0,2.5,0.3,3.4,1.1c1.3,1.2,1.5,2.8,1.5,5.1h-7.6c0,2.3,1.1,3.4,3.1,3.4c1.3,0,2.7-0.3,4.1-0.6v1.8
+			C161.5,58.1,159.8,58.5,158.2,58.5 M158.4,48.7c-1.9,0-2.5,1.2-2.6,3.1h5.3C161,49.7,160.3,48.7,158.4,48.7"/>
+		<path style="fill:#FFFFFF;" d="M172,58.5c-1.5,0-3.1-0.4-4.2-1.6c-1.4-1.4-1.9-3.5-1.9-6c0-2.4,0.7-4.8,2.5-6.3
+			c1.4-1.1,3.1-1.3,4.9-1.3c1.1,0,2.2,0.1,3.4,0.2v2.1c-1-0.1-2.2-0.2-3.2-0.2c-3.8,0-5.1,2.1-5.1,5.5c0,3.3,1.4,5.4,4.3,5.4
+			c1.3,0,2.9-0.4,4.2-0.8v2.1C175.3,58.1,173.6,58.5,172,58.5"/>
+		<path style="fill:#FFFFFF;" d="M181.1,57.4c-1.1-0.9-1.6-2.5-1.6-4.6s0.5-3.6,1.6-4.6c1-0.9,2.3-1.1,3.8-1.1
+			c1.4,0,2.7,0.3,3.8,1.1c1.1,0.9,1.6,2.5,1.6,4.5c0,2.1-0.5,3.6-1.6,4.6c-1,0.9-2.4,1.1-3.8,1.1C183.5,58.5,182.1,58.2,181.1,57.4
+			 M187.9,52.8c0-2.6-0.9-3.9-3-3.9c-2.2,0-3,1.2-3,3.8c0,2.6,0.9,4,3,4C187.1,56.7,187.9,55.5,187.9,52.8"/>
+		<path style="fill:#FFFFFF;" d="M201.3,58.2v-6.8c0-1.8-0.9-2.4-2.4-2.4c-0.8,0-1.8,0.2-2.9,0.7v8.5h-2.3V47.4h2l0.1,0.6
+			c1.4-0.4,2.7-0.9,4-0.9c1.2,0,2.3,0.3,3.1,1.2c0.7,0.8,0.9,1.8,0.9,3.1v6.8H201.3z"/>
+		<path style="fill:#FFFFFF;" d="M215.5,58.2v-6.8c0-1.8-0.9-2.4-2.4-2.4c-0.8,0-1.8,0.2-2.9,0.7v8.5h-2.3V47.4h2l0.1,0.6
+			c1.4-0.4,2.7-0.9,4-0.9c1.2,0,2.3,0.3,3.1,1.2c0.7,0.8,0.9,1.8,0.9,3.1v6.8H215.5z"/>
+		<path style="fill:#FFFFFF;" d="M225.8,58.5c-1.2,0-2.5-0.3-3.5-1.2c-1-1-1.4-2.6-1.4-4.5c0-1.8,0.4-3.5,1.6-4.6
+			c0.9-0.8,2-1.1,3.5-1.1c1.2,0,2.5,0.3,3.4,1.1c1.3,1.2,1.5,2.8,1.5,5.1h-7.6c0,2.3,1.1,3.4,3.1,3.4c1.3,0,2.7-0.3,4.1-0.6v1.8
+			C229.1,58.1,227.4,58.5,225.8,58.5 M226,48.7c-1.9,0-2.5,1.2-2.6,3.1h5.3C228.5,49.7,227.8,48.7,226,48.7"/>
+		<path style="fill:#FFFFFF;" d="M238.1,58.5c-1.1,0-2.3-0.3-3.2-1.2c-1-1-1.4-2.6-1.4-4.4c0-1.8,0.5-3.6,1.9-4.7c1-0.8,2.3-1,3.7-1
+			c0.8,0,1.7,0.1,2.7,0.2v1.9c-0.7-0.1-1.6-0.1-2.4-0.1c-2.4,0-3.4,1.2-3.4,3.8c0,2.3,0.9,3.8,2.9,3.8c0.9,0,2.1-0.3,3.1-0.6v1.8
+			C240.7,58.2,239.3,58.5,238.1,58.5"/>
+		<path style="fill:#FFFFFF;" d="M248.8,58.5c-1.2,0-2.3-0.4-2.9-1.7c-0.4-0.8-0.5-1.8-0.5-3v-4.6h-1.7v-1.8h1.7l0.3-3.3h2.1v3.3
+			h3.1v1.8h-3.1v4.2c0,0.8,0,1.5,0.2,2c0.2,0.8,0.7,1.1,1.6,1.1c0.5,0,1.1-0.1,1.6-0.2v1.8C250.3,58.3,249.5,58.5,248.8,58.5"/>
+	</g>
+	<g>
+		<polygon style="fill:#FFFFFF;" points="18,22 18,56.9 48.2,74.4 78.5,56.9 78.5,22 48.2,4.5 		"/>
+		<g>
+			<path style="fill:#1B1464;" d="M48.2,3.3L17,21.4v36.1l31.3,18l31.3-18V21.4L48.2,3.3z M78.5,56.9L48.2,74.4L18,56.9V22L48.2,4.5
+				L78.5,22V56.9z"/>
+		</g>
+		<polygon style="fill:#0069CC;" points="62.6,20.8 48.9,12.9 35.2,20.8 25.9,26.2 25.9,26.2 25.9,52.7 25.9,52.7 48.9,66 
+			71.9,52.7 71.9,52.7 71.9,26.2 71.9,26.2 		"/>
+		<g>
+			<polygon style="fill:#034EA2;" points="64.3,39.4 56,25.1 48.9,12.9 48.9,29.6 48.9,66 71.9,52.7 71.9,52.7 			"/>
+			<polygon style="fill:#0069CC;" points="56,25.1 64.3,39.4 71.9,26.2 71.9,26.2 62.6,20.8 			"/>
+			<polygon style="fill:#ED1C24;" points="62.6,20.8 48.9,12.9 56,25.1 			"/>
+			<polygon style="fill:#0069CC;" points="56,25.1 48.9,12.9 56,25.1 			"/>
+			<rect x="60.1" y="24" style="fill:#0069CC;" width="0" height="16.6"/>
+			<polygon style="fill:#ED1C24;" points="71.9,52.7 71.9,26.2 64.3,39.4 			"/>
+			<polygon style="fill:#ED1C24;" points="64.3,39.4 71.9,52.7 64.3,39.4 			"/>
+			<polygon style="fill:#0069CC;" points="33.6,39.4 41.9,25.1 48.9,12.9 48.9,29.6 48.9,66 25.9,52.7 25.9,52.7 			"/>
+			<polygon style="fill:#ED1C24;" points="41.9,25.1 33.6,39.4 25.9,26.2 25.9,26.2 35.2,20.8 			"/>
+			<polygon style="fill:#034EA2;" points="35.2,20.8 48.9,12.9 41.9,25.1 			"/>
+			<polygon style="fill:#0069CC;" points="41.9,25.1 48.9,12.9 41.9,25.1 			"/>
+			<rect x="37.7" y="24" style="fill:#0069CC;" width="0" height="16.6"/>
+			<polygon style="fill:#034EA2;" points="25.9,52.7 25.9,26.2 33.6,39.4 			"/>
+			<polygon style="fill:#0069CC;" points="33.6,39.4 25.9,52.7 33.6,39.4 			"/>
+		</g>
+		<g>
+			<path style="fill:#034EA2;" d="M57.4,42c0.4,0,0.8-0.1,1.2,0c0.3,0.1,0.7,0.1,0.7,0.2c-0.1,0.6-1,0.7-1.4,1.3c-0.1,0-0.1,0-0.2,0
+				c-0.2,0.1-0.1,0.5-0.3,0.5c-0.2-0.1-0.4,0-0.7,0.1c0.3,0.3,0.7,0.5,1.1,0.4c0.1,0,0.2,0.1,0.2,0.3c0,0,0.1,0,0.1-0.1
+				c0.1,0,0.1,0,0.1,0.1c0,0.1,0,0.2,0,0.3c-0.2,0.3-0.6,0.2-0.9,0.2c0.6,0.1,1.2,0.1,1.7,0c0.4-0.2,0-0.9,0.3-1.2
+				c-0.1,0,0-0.2-0.2-0.2c0.1-0.1,0.3-0.4,0.4-0.4c0.1,0,0.4-0.1,0.4-0.2c0-0.1-0.3-0.2-0.2-0.4c0.4-0.3,0.8-0.7,0.6-1.2
+				c-0.1-0.2-0.7-0.2-1-0.3c-0.4-0.1-0.8,0-1.2,0.1c-0.4,0-0.7,0.2-1.1,0.3c-0.5,0.2-0.9,0.5-1.4,0.8C56.3,42.3,56.8,42.2,57.4,42z"
+				/>
+			<path style="fill:#FFFFFF;" d="M63,46.4c-0.2-0.4-0.5-0.7-0.8-1.1c-0.3-0.5-0.7-0.9-0.8-1.5c-0.2-0.6,0-1.1,0-1.7
+				c0-1.1-0.3-2.2-0.6-3.2c-0.2-0.5-0.3-1.1-0.5-1.6c-0.1-0.3-0.2-0.6-0.4-0.9c-0.1-0.1-0.1-0.4,0-0.5c0.3-0.2,0.6-0.5,0.8-0.7
+				c0.2-0.4,0-0.9-0.3-1.1c-0.5-0.2-0.4,0.5-0.8,0.7c-0.1,0-0.1,0-0.2,0c-0.1-0.2,0.1-0.3,0.2-0.4c0-0.1,0-0.2-0.1-0.2
+				c-0.3,0-0.6-0.1-0.7-0.2c-0.8-1-1.8-1.5-2.9-1.9c0.3,0.1,0.6,0.1,0.9,0.1c0.5,0.1,1.1,0,1.5-0.2c0.4-0.2,0.4-0.7,0.5-1.1
+				c0.1-0.1,0-0.2,0-0.4c0-0.2-0.2-0.4-0.3-0.6c0,0-0.1-0.1-0.2-0.3c-0.8-0.9-3.9-3.5-9.7-3.1c-2.5,0.2-5.6,0.9-9.2,2.7
+				c-0.1,0-0.2,0.1-0.4,0.1c-0.6,0.3-1.4,0.8-1.9,1.4c-0.6,0.7-1.1,1.5-1.3,2.4c-0.9,0.6-1.5,1.5-2,2.4c-0.6,1.2-1.4,2.2-1.4,3.5
+				c0,0.1,0,0.2,0,0.2c0.1,0.4,0.1,0.7,0.2,1.1c0.2,0.8,0.4,1.6,0.5,2.4c0.1,0.4,0.2,0.8,0.3,1.2c0.2,0.4,0,0.9,0.3,1.3
+				c0.1,0.2,0.1,0.5,0.4,0.6c0,0.1,0,0.2,0,0.3c0.1,0.1,0.1,0.1,0.2,0.1c0,0.1,0,0.2,0,0.3c0.6,0.7,1.3,1.3,1.7,2.1
+				c0.2,0.4-0.7,0.2-1.1,0.1c-0.7-0.3-1.2-0.9-1.8-1.4c0,0-0.1,0.1-0.1,0.1c0.3,0.5,1.4,1.1,0.8,1.5c-0.3,0.2-0.7-0.2-0.9,0.1
+				c-0.1,0.1,0,0.3,0,0.4c-0.4-0.3-0.9-0.1-1.3-0.3c-0.3-0.1-0.4-0.6-0.7-0.6c-0.9-0.2-1.8-0.4-2.8-0.4c-0.1,0-0.2,0-0.2,0
+				c-0.9-0.1-1.8-0.2-2.6-0.1V49c0.8-0.2,1.6-0.4,2.4-0.4c0.1,0,0.2,0,0.2,0c0.2,0,0.5-0.1,0.7,0c-0.3,0-0.7,0-1,0.1
+				c-0.8,0.1-1.6,0.4-2.4,0.7v1c0.4,0.1,0.9,0.1,1.3,0.2c0.5,0.1,1,0.2,1.5,0.4c0.7,0.2,1.2,0.5,1.8,0.8c0.3,0.2,0.4,0.4,0.7,0.6
+				c0.4,0.2,0.9,0.2,1.2,0c0.1,0,0.3,0,0.4,0c1.1-0.3,2.2-0.6,2.9-1.5c0,0.1,0.1,0.1,0.1,0.1c-0.2,0.6-0.2,1.2-0.6,1.8
+				c0,0.1-0.1,0.2,0.1,0.3c0.1,0,0.1,0,0.1,0c-0.1,0-0.1,0-0.1,0.1c0,0.1,0.2,0,0.3,0.1c-0.4,0.1-0.7,0.2-0.9,0.5
+				c0,0.1,0.1,0.1,0.2,0.1c-0.1,0.1-0.4,0.1-0.4,0.2c0,0,0.1,0.1,0.1,0.1c-0.1,0-0.1,0-0.1,0.1c0,0.1,0,0.1,0,0.2
+				c-0.2,0-0.3,0.2-0.4,0.2c0.3,0.2,0.5,0,0.8,0c-0.8,0.3-1.4,0.8-2.2,1c-0.1,0,0,0.2-0.1,0.2c0.2,0.1,0.4-0.1,0.6-0.1
+				c-0.4,0.3-0.8,0.5-1.2,0.7l2.4,1.4c1-0.6,1.9-1.3,2.7-2.2c0,0,0.1,0.1,0.1,0.1c-0.2,0.7-0.6,1.2-1.2,1.7c-0.4,0.2-0.7,0.6-1,0.7
+				l1.8,1c0.4-0.3,0.7-0.5,1.2-0.7c0.1,0,0.2,0.1,0.4,0.1c0.6-0.6,1.3-1.3,2.3-1.1c0,0.1,0,0.1,0.1,0.1c0,0,0,0,0,0
+				c0,0,0.1,0,0.1-0.1c0,0.1,0,0.1-0.1,0.1c-0.3,0.2-0.5,0.4-0.8,0.6c-0.1,0.1,0,0.1,0.1,0.1c0.4-0.2,0.6-0.4,0.9-0.6
+				c-0.1,0.1-0.1,0.2-0.1,0.3c-0.9,0.7-1.6,1.4-2.3,2.2l9.5,5.5c0.3-0.4,0.7-1,1.1-1.5c1.8-2.6,4.4-6.1,5.2-6.9
+				c0.3-0.2,0.6-0.2,1-0.3c1.2,0,2.5,0.3,3.7,0.4c0.1,0,0.3,0.1,0.4,0.1c0.4,0.1,0.9,0,1.4-0.1c0.5-0.2,1.1-0.5,1.3-1.1
+				c0.2-0.5,0.3-1.1,0-1.6c-0.5-0.6,0.4-0.9,0.7-1.3c0.2-0.4-0.2-0.6-0.2-0.9c-0.1-0.1-0.4-0.1-0.5-0.3c0.5-0.2,1.3-0.7,0.9-1.3
+				c-0.2-0.4-0.6-0.9-0.2-1.3c0.5-0.3,1.3-0.3,1.5-0.8C64.3,47.8,63.4,47.1,63,46.4z M59.9,42.8c-0.1,0.1,0.2,0.2,0.2,0.4
+				c-0.1,0.1-0.3,0.2-0.4,0.2c-0.1,0.1-0.3,0.3-0.4,0.4c0.1,0,0,0.2,0.2,0.2c-0.3,0.4,0.2,1.1-0.3,1.2c-0.5,0.2-1.1,0.2-1.7,0
+				c0.3-0.1,0.7,0.1,0.9-0.2c0-0.1,0-0.2,0-0.3c0-0.1-0.1-0.1-0.1-0.1c-0.1,0.1-0.1,0.1-0.1,0.1c0-0.1-0.2-0.3-0.2-0.3
+				c-0.4,0.1-0.8-0.1-1.1-0.4c0.2-0.1,0.4-0.2,0.7-0.1c0.2,0,0.1-0.4,0.3-0.5c0.1,0,0.1,0,0.2,0c0.4-0.6,1.3-0.8,1.4-1.3
+				c0-0.1-0.4-0.1-0.7-0.2c-0.4-0.1-0.8,0-1.2,0c-0.6,0.2-1.1,0.2-1.6,0.5c0.4-0.3,0.9-0.6,1.4-0.8c0.4-0.1,0.7-0.3,1.1-0.3
+				c0.4-0.1,0.9-0.2,1.2-0.1c0.4,0.1,0.9,0.1,1,0.3C60.6,42.1,60.3,42.5,59.9,42.8z"/>
+		</g>
+	</g>
+</g>
+</svg>
diff --git a/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/resources/views/login.html b/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/resources/views/login.html
index b9183d657b..110ae0a1a6 100644
--- a/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/resources/views/login.html
+++ b/gravitee-am-management-api/gravitee-am-management-api-rest/src/main/resources/views/login.html
@@ -63,7 +63,10 @@
                     <a th:href="${authorizeUrls.get(socialProvider.getId())}"
                        th:class="'mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect btn-' + ${socialProvider.getType()}"
                        th:each="socialProvider : ${socialProviders}">
-                        <i th:class="'fa fa-' + ${socialProvider.getType()}"></i> <span th:text="${socialProvider.getName()}"></span>
+                        <img th:if="${socialProvider.getType()} == 'franceconnect'" th:src="@{assets/images/FCboutons-10.svg}" height="70">
+                        <span th:if="${socialProvider.getType()} != 'franceconnect'">
+                                <i th:class="'fa fa-' + ${socialProvider.getType()}"></i> <span th:text="${socialProvider.getName()}"></span>
+                            </span>
                     </a>
                 </div>
             </div>
diff --git a/gravitee-am-management-api/gravitee-am-management-api-standalone/gravitee-am-management-api-standalone-distribution/pom.xml b/gravitee-am-management-api/gravitee-am-management-api-standalone/gravitee-am-management-api-standalone-distribution/pom.xml
index 7a966fa288..f57e8d6c28 100644
--- a/gravitee-am-management-api/gravitee-am-management-api-standalone/gravitee-am-management-api-standalone-distribution/pom.xml
+++ b/gravitee-am-management-api/gravitee-am-management-api-standalone/gravitee-am-management-api-standalone-distribution/pom.xml
@@ -116,6 +116,14 @@
             <scope>runtime</scope>
         </dependency>
 
+        <dependency>
+            <groupId>io.gravitee.am.identityprovider</groupId>
+            <artifactId>gravitee-am-identityprovider-franceconnect</artifactId>
+            <version>${project.version}</version>
+            <type>zip</type>
+            <scope>runtime</scope>
+        </dependency>
+
         <dependency>
             <groupId>io.gravitee.am.certificate</groupId>
             <artifactId>gravitee-am-certificate-javakeystore</artifactId>
@@ -291,6 +299,12 @@
                                     <version>${project.version}</version>
                                     <type>zip</type>
                                 </artifactItem>
+                                <artifactItem>
+                                    <groupId>io.gravitee.am.identityprovider</groupId>
+                                    <artifactId>gravitee-am-identityprovider-franceconnect</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>zip</type>
+                                </artifactItem>
 
                                 <!-- Certificates -->
                                 <artifactItem>
diff --git a/gravitee-am-ui/src/app/domain/applications/application/idp/idp.component.ts b/gravitee-am-ui/src/app/domain/applications/application/idp/idp.component.ts
index cdb7e92083..44979561bf 100644
--- a/gravitee-am-ui/src/app/domain/applications/application/idp/idp.component.ts
+++ b/gravitee-am-ui/src/app/domain/applications/application/idp/idp.component.ts
@@ -35,7 +35,8 @@ export class ApplicationIdPComponent implements OnInit {
     'github-am-idp': 'GitHub',
     'azure-ad-am-idp': 'Azure AD',
     'twitter-am-idp': 'Twitter',
-    'facebook-am-idp': 'Facebook'
+    'facebook-am-idp': 'Facebook',
+    'franceconnect-am-idp': 'FranceConnect'
   };
   private identityProviderIcons: any = {
     'ldap-am-idp' : 'device_hub',
@@ -45,7 +46,8 @@ export class ApplicationIdPComponent implements OnInit {
     'github-am-idp': 'cloud_queue',
     'azure-ad-am-idp': 'cloud_queue',
     'twitter-am-idp': 'cloud_queue',
-    'facebook-am-idp': 'cloud_queue'
+    'facebook-am-idp': 'cloud_queue',
+    'franceconnect-am-idp': 'cloud_queue'
   };
   loadIdentities = true;
   application: any;
diff --git a/gravitee-am-ui/src/app/domain/settings/providers/creation/steps/step1/step1.component.ts b/gravitee-am-ui/src/app/domain/settings/providers/creation/steps/step1/step1.component.ts
index 2e421b9724..91c283ddca 100644
--- a/gravitee-am-ui/src/app/domain/settings/providers/creation/steps/step1/step1.component.ts
+++ b/gravitee-am-ui/src/app/domain/settings/providers/creation/steps/step1/step1.component.ts
@@ -32,7 +32,8 @@ export class ProviderCreationStep1Component implements OnInit {
     'github-am-idp': 'GitHub',
     'facebook-am-idp': 'Facebook',
     'http-am-idp': 'HTTP',
-    'saml2-generic-am-idp': 'SAML 2.0'
+    'saml2-generic-am-idp': 'SAML 2.0',
+    'franceconnect-am-idp': 'FranceConnect'
   };
   @Input() provider;
   providers: any[];
diff --git a/gravitee-am-ui/src/app/domain/settings/providers/providers.component.ts b/gravitee-am-ui/src/app/domain/settings/providers/providers.component.ts
index 2a66ab0b15..fbf6f8b477 100644
--- a/gravitee-am-ui/src/app/domain/settings/providers/providers.component.ts
+++ b/gravitee-am-ui/src/app/domain/settings/providers/providers.component.ts
@@ -37,7 +37,8 @@ export class DomainSettingsProvidersComponent implements OnInit {
     'github-am-idp': 'GitHub',
     'azure-ad-am-idp': 'Azure AD',
     'twitter-am-idp': 'Twitter',
-    'facebook-am-idp': 'Facebook'
+    'facebook-am-idp': 'Facebook',
+    'franceconnect-am-idp': 'FranceConnect'
   };
   private identityProviderIcons: any = {
     'ldap-am-idp' : 'device_hub',
@@ -47,7 +48,8 @@ export class DomainSettingsProvidersComponent implements OnInit {
     'github-am-idp': 'cloud_queue',
     'azure-ad-am-idp': 'cloud_queue',
     'twitter-am-idp': 'cloud_queue',
-    'facebook-am-idp': 'cloud_queue'
+    'facebook-am-idp': 'cloud_queue',
+    'franceconnect-am-idp': 'cloud_queue'
   };
   domainId: string;
 


Test patch:
diff --git a/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/test/java/io/gravitee/am/identityprovider/franceconnect/authentication/DummyAuthenticationContext.java b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/test/java/io/gravitee/am/identityprovider/franceconnect/authentication/DummyAuthenticationContext.java
new file mode 100644
index 0000000000..d655df5584
--- /dev/null
+++ b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/test/java/io/gravitee/am/identityprovider/franceconnect/authentication/DummyAuthenticationContext.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
+ *
+ * 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 io.gravitee.am.identityprovider.franceconnect.authentication;
+
+import io.gravitee.am.identityprovider.api.AuthenticationContext;
+import io.gravitee.el.TemplateEngine;
+import io.gravitee.gateway.api.Request;
+import io.gravitee.gateway.api.Response;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Map;
+
+/**
+ * @author David BRASSELY (david.brassely at graviteesource.com)
+ * @author GraviteeSource Team
+ */
+public class DummyAuthenticationContext implements AuthenticationContext {
+
+    private final Map<String, Object> attributes;
+    private final Request request;
+
+    DummyAuthenticationContext(Map<String, Object> attributes, Request request) {
+        this.attributes = attributes;
+        this.request = request;
+    }
+
+    @Override
+    public Request request() {
+        return request;
+    }
+
+    @Override
+    public Response response() {
+        throw new IllegalStateException();
+    }
+
+    @Override
+    public <T> T getComponent(Class<T> componentClass) {
+        throw new IllegalStateException();
+    }
+
+    @Override
+    public void setAttribute(String name, Object value) {
+        attributes.put(name, value);
+    }
+
+    @Override
+    public void removeAttribute(String name) {
+        attributes.remove(name);
+    }
+
+    @Override
+    public Object getAttribute(String name) {
+        return attributes.get(name);
+    }
+
+    @Override
+    public Enumeration<String> getAttributeNames() {
+        return Collections.enumeration(attributes.keySet());
+    }
+
+    @Override
+    public Map<String, Object> getAttributes() {
+        return attributes;
+    }
+
+    @Override
+    public TemplateEngine getTemplateEngine() {
+        throw new IllegalStateException();
+    }
+}
diff --git a/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/test/java/io/gravitee/am/identityprovider/franceconnect/authentication/DummyRequest.java b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/test/java/io/gravitee/am/identityprovider/franceconnect/authentication/DummyRequest.java
new file mode 100644
index 0000000000..de90891c92
--- /dev/null
+++ b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/test/java/io/gravitee/am/identityprovider/franceconnect/authentication/DummyRequest.java
@@ -0,0 +1,165 @@
+/**
+ * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
+ *
+ * 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 io.gravitee.am.identityprovider.franceconnect.authentication;
+
+import io.gravitee.common.http.HttpHeaders;
+import io.gravitee.common.http.HttpMethod;
+import io.gravitee.common.http.HttpVersion;
+import io.gravitee.common.util.LinkedMultiValueMap;
+import io.gravitee.common.util.MultiValueMap;
+import io.gravitee.gateway.api.Request;
+import io.gravitee.gateway.api.buffer.Buffer;
+import io.gravitee.gateway.api.handler.Handler;
+import io.gravitee.gateway.api.stream.ReadStream;
+import io.gravitee.gateway.api.ws.WebSocket;
+import io.gravitee.reporter.api.http.Metrics;
+
+import javax.net.ssl.SSLSession;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author David BRASSELY (david.brassely at graviteesource.com)
+ * @author GraviteeSource Team
+ */
+public class DummyRequest implements Request {
+
+    private MultiValueMap queryParameters;
+
+    @Override
+    public String id() {
+        return null;
+    }
+
+    @Override
+    public String transactionId() {
+        return null;
+    }
+
+    @Override
+    public String uri() {
+        return null;
+    }
+
+    @Override
+    public String path() {
+        return null;
+    }
+
+    @Override
+    public String pathInfo() {
+        return null;
+    }
+
+    @Override
+    public String contextPath() {
+        return null;
+    }
+
+    @Override
+    public MultiValueMap<String, String> parameters() {
+       return queryParameters;
+    }
+
+    public void setParameters(Map<String, List<String>> parameters) {
+        queryParameters = new LinkedMultiValueMap(parameters);
+    }
+
+    @Override
+    public HttpHeaders headers() {
+        return null;
+    }
+
+    @Override
+    public HttpMethod method() {
+        return null;
+    }
+
+    @Override
+    public String scheme() {
+        return null;
+    }
+
+    @Override
+    public String rawMethod() {
+        return null;
+    }
+
+    @Override
+    public HttpVersion version() {
+        return null;
+    }
+
+    @Override
+    public long timestamp() {
+        return 0;
+    }
+
+    @Override
+    public String remoteAddress() {
+        return null;
+    }
+
+    @Override
+    public String localAddress() {
+        return null;
+    }
+
+    @Override
+    public SSLSession sslSession() {
+        return null;
+    }
+
+    @Override
+    public Metrics metrics() {
+        return null;
+    }
+
+    @Override
+    public boolean ended() {
+        return false;
+    }
+
+    @Override
+    public Request timeoutHandler(Handler<Long> timeoutHandler) {
+        return null;
+    }
+
+    @Override
+    public Handler<Long> timeoutHandler() {
+        return null;
+    }
+
+    @Override
+    public boolean isWebSocket() {
+        return false;
+    }
+
+    @Override
+    public WebSocket websocket() {
+        return null;
+    }
+
+    @Override
+    public ReadStream<Buffer> bodyHandler(Handler<Buffer> bodyHandler) {
+        return null;
+    }
+
+    @Override
+    public ReadStream<Buffer> endHandler(Handler<Void> endHandler) {
+        return null;
+    }
+}
diff --git a/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/test/java/io/gravitee/am/identityprovider/franceconnect/authentication/FranceConnectAuthenticationProviderTest.java b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/test/java/io/gravitee/am/identityprovider/franceconnect/authentication/FranceConnectAuthenticationProviderTest.java
new file mode 100644
index 0000000000..a6c57eac09
--- /dev/null
+++ b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/test/java/io/gravitee/am/identityprovider/franceconnect/authentication/FranceConnectAuthenticationProviderTest.java
@@ -0,0 +1,207 @@
+/**
+ * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
+ *
+ * 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 io.gravitee.am.identityprovider.franceconnect.authentication;
+
+import com.github.tomakehurst.wiremock.junit.WireMockRule;
+import io.gravitee.am.common.exception.authentication.BadCredentialsException;
+import io.gravitee.am.identityprovider.api.*;
+import io.gravitee.am.identityprovider.common.oauth2.utils.URLEncodedUtils;
+import io.gravitee.am.identityprovider.franceconnect.authentication.spring.FranceConnectAuthenticationProviderConfiguration;
+import io.gravitee.common.http.HttpHeaders;
+import io.reactivex.observers.TestObserver;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.AnnotationConfigContextLoader;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.*;
+import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
+
+/**
+ * @author David BRASSELY (david.brassely at graviteesource.com)
+ * @author GraviteeSource Team
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = { FranceConnectAuthenticationProviderTestConfiguration.class, FranceConnectAuthenticationProviderConfiguration.class }, loader = AnnotationConfigContextLoader.class)
+public class FranceConnectAuthenticationProviderTest {
+
+    @Autowired
+    private AuthenticationProvider authenticationProvider;
+
+    @Autowired
+    private DefaultIdentityProviderRoleMapper roleMapper;
+
+    @Rule
+    public WireMockRule wireMockRule = new WireMockRule(wireMockConfig().port(19998));
+
+    @Test
+    public void shouldLoadUserByUsername_authentication() {
+        stubFor(any(urlPathEqualTo("/oauth/token"))
+                .withHeader(HttpHeaders.CONTENT_TYPE, containing(URLEncodedUtils.CONTENT_TYPE))
+                .withRequestBody(matching(".*"))
+                .willReturn(aResponse()
+                        .withStatus(200)
+                        .withBody("{\"access_token\":\"test_token\",\"token_type\":\"bearer\"}")));
+
+        stubFor(any(urlPathEqualTo("/profile"))
+                .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Bearer test_token"))
+                .willReturn(okJson("{ \"preferred_username\": \"bob\" }")));
+
+        TestObserver<User> testObserver = authenticationProvider.loadUserByUsername(new Authentication() {
+            @Override
+            public Object getCredentials() {
+                return "__social__";
+            }
+
+            @Override
+            public Object getPrincipal() {
+                return "__social__";
+            }
+
+            @Override
+            public AuthenticationContext getContext() {
+                DummyRequest dummyRequest = new DummyRequest();
+                dummyRequest.setParameters(Collections.singletonMap("code", Arrays.asList("test-code")));
+                return new DummyAuthenticationContext(Collections.singletonMap("redirect_uri", "http://redirect_uri"), dummyRequest);
+            }
+        }).test();
+
+        testObserver.awaitTerminalEvent();
+
+        testObserver.assertComplete();
+        testObserver.assertNoErrors();
+        testObserver.assertValue(u -> "bob".equals(u.getUsername()));
+    }
+
+    @Test
+    public void shouldLoadUserByUsername_authentication_badCredentials() {
+        stubFor(any(urlPathEqualTo("/oauth/token"))
+                .withHeader(HttpHeaders.CONTENT_TYPE, containing(URLEncodedUtils.CONTENT_TYPE))
+                .withRequestBody(matching(".*"))
+                .willReturn(unauthorized()));
+
+        TestObserver<User> testObserver = authenticationProvider.loadUserByUsername(new Authentication() {
+            @Override
+            public Object getCredentials() {
+                return "__social__";
+            }
+
+            @Override
+            public Object getPrincipal() {
+                return "__social__";
+            }
+
+            @Override
+            public AuthenticationContext getContext() {
+                DummyRequest dummyRequest = new DummyRequest();
+                dummyRequest.setParameters(Collections.singletonMap("code", Arrays.asList("wrong-code")));
+                return new DummyAuthenticationContext(Collections.singletonMap("redirect_uri", "http://redirect_uri"), dummyRequest);
+            }
+        }).test();
+        testObserver.awaitTerminalEvent();
+
+        testObserver.assertError(BadCredentialsException.class);
+    }
+
+    @Test
+    public void shouldLoadUserByUsername_authentication_usernameNotFound() {
+        stubFor(any(urlPathEqualTo("/oauth/token"))
+                .withHeader(HttpHeaders.CONTENT_TYPE, containing(URLEncodedUtils.CONTENT_TYPE))
+                .withRequestBody(matching(".*"))
+                .willReturn(aResponse()
+                        .withStatus(200)
+                        .withBody("{\"access_token\":\"test_token\",\"token_type\":\"bearer\"}")));
+
+        stubFor(any(urlPathEqualTo("/profile"))
+                .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Bearer test_token"))
+                .willReturn(notFound()));
+
+        TestObserver<User> testObserver = authenticationProvider.loadUserByUsername(new Authentication() {
+            @Override
+            public Object getCredentials() {
+                return "__social__";
+            }
+
+            @Override
+            public Object getPrincipal() {
+                return "__social__";
+            }
+
+            @Override
+            public AuthenticationContext getContext() {
+                DummyRequest dummyRequest = new DummyRequest();
+                dummyRequest.setParameters(Collections.singletonMap("code", Arrays.asList("test-code")));
+                return new DummyAuthenticationContext(Collections.singletonMap("redirect_uri", "http://redirect_uri"), dummyRequest);
+            }
+        }).test();
+        testObserver.awaitTerminalEvent();
+
+        testObserver.assertError(BadCredentialsException.class);
+    }
+
+    @Test
+    public void shouldLoadUserByUsername_roleMapping() {
+        // configure role mapping
+        Map<String, String[]> roles = new HashMap<>();
+        roles.put("admin", new String[] { "preferred_username=bob"});
+        roleMapper.setRoles(roles);
+
+        stubFor(any(urlPathEqualTo("/oauth/token"))
+                .withHeader(HttpHeaders.CONTENT_TYPE, containing(URLEncodedUtils.CONTENT_TYPE))
+                .withRequestBody(matching(".*"))
+                .willReturn(aResponse()
+                        .withStatus(200)
+                        .withBody("{\"access_token\":\"test_token\",\"token_type\":\"bearer\"}")));
+
+        stubFor(any(urlPathEqualTo("/profile"))
+                .withHeader(HttpHeaders.AUTHORIZATION, equalTo("Bearer test_token"))
+                .willReturn(okJson("{ \"login\": \"bob\", \"preferred_username\": \"bob\"}")));
+
+        TestObserver<User> testObserver = authenticationProvider.loadUserByUsername(new Authentication() {
+            @Override
+            public Object getCredentials() {
+                return "__social__";
+            }
+
+            @Override
+            public Object getPrincipal() {
+                return "__social__";
+            }
+
+            @Override
+            public AuthenticationContext getContext() {
+                DummyRequest dummyRequest = new DummyRequest();
+                dummyRequest.setParameters(Collections.singletonMap("code", Arrays.asList("test-code")));
+                return new DummyAuthenticationContext(Collections.singletonMap("redirect_uri", "http://redirect_uri"), dummyRequest);
+            }
+        }).test();
+
+        testObserver.awaitTerminalEvent();
+
+        testObserver.assertComplete();
+        testObserver.assertNoErrors();
+        testObserver.assertValue(u -> "bob".equals(u.getUsername()));
+        testObserver.assertValue(u -> u.getRoles().contains("admin"));
+    }
+}
diff --git a/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/test/java/io/gravitee/am/identityprovider/franceconnect/authentication/FranceConnectAuthenticationProviderTestConfiguration.java b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/test/java/io/gravitee/am/identityprovider/franceconnect/authentication/FranceConnectAuthenticationProviderTestConfiguration.java
new file mode 100644
index 0000000000..9f33c1e519
--- /dev/null
+++ b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/test/java/io/gravitee/am/identityprovider/franceconnect/authentication/FranceConnectAuthenticationProviderTestConfiguration.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
+ *
+ * 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 io.gravitee.am.identityprovider.franceconnect.authentication;
+
+import io.gravitee.am.identityprovider.api.AuthenticationProvider;
+import io.gravitee.am.identityprovider.api.DefaultIdentityProviderMapper;
+import io.gravitee.am.identityprovider.api.DefaultIdentityProviderRoleMapper;
+import io.gravitee.am.identityprovider.franceconnect.FranceConnectIdentityProviderConfiguration;
+import io.vertx.reactivex.core.Vertx;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Properties;
+
+/**
+ * @author David BRASSELY (david.brassely at graviteesource.com)
+ * @author GraviteeSource Team
+ */
+@Configuration
+public class FranceConnectAuthenticationProviderTestConfiguration {
+
+    @Bean
+    public FranceConnectIdentityProviderConfiguration githubIdentityProviderConfiguration() {
+        FranceConnectIdentityProviderConfiguration configuration = new FranceConnectIdentityProviderConfiguration();
+
+        configuration.setClientId("test-client-id");
+        configuration.setClientSecret("test-client-secret");
+        configuration.setAccessTokenUri("http://localhost:19998/oauth/token");
+        configuration.setUserAuthorizationUri("http://localhost:19998/oauth/authorize");
+        configuration.setUserProfileUri("http://localhost:19998/profile");
+        configuration.setEnvironment(FranceConnectIdentityProviderConfiguration.Environment.TEST);
+        return configuration;
+    }
+
+    @Bean
+    public AuthenticationProvider authenticationProvider() {
+        return new FranceConnectAuthenticationProvider();
+    }
+
+    @Bean("graviteeProperties")
+    public Properties properties() {
+        return new Properties();
+    }
+
+    @Bean
+    public Vertx vertx() {
+        return Vertx.vertx();
+    }
+
+    @Bean
+    public DefaultIdentityProviderRoleMapper roleMapper() {
+        return new DefaultIdentityProviderRoleMapper();
+    }
+
+    @Bean
+    public DefaultIdentityProviderMapper mapper() {
+        return new DefaultIdentityProviderMapper();
+    }
+}
diff --git a/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/test/resources/logback.xml b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/test/resources/logback.xml
new file mode 100644
index 0000000000..945f2e19e7
--- /dev/null
+++ b/gravitee-am-identityprovider/gravitee-am-identityprovider-franceconnect/src/test/resources/logback.xml
@@ -0,0 +1,14 @@
+<configuration>
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d{HH:mm:ss.SSS} [%thread] [%X{domain}] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <logger name="io.gravitee" level="INFO"/>
+
+    <root level="ERROR">
+        <appender-ref ref="STDOUT"/>
+    </root>
+</configuration>
\ No newline at end of file