Moqui SSO now available

We’re happy to announce the availablity of Moqui SSO. This new feature is for anyone looking to add new login options to Moqui. The new Moqui SSO component supports the following protocols:

  1. OAuth
  2. OpenID Connect
  3. SAML

How to enable Moqui SSO?
You can enable SSO by following these 2 simple steps:

  1. Get the SSO component
./gradlew getComponent -Pcomponent=moqui-sso
  1. Load the seed data (pick the flow you wish to enable):
<entity-facade-xml>
	<moqui.security.sso.AuthFlow authFlowId="Keycloak" authFlowTypeEnumId="AftOidc" description="Keycloak" defaultUserGroupId="ALL_USERS" sequenceNum="1" iconName="security">
		<oidc clientTypeEnumId="OctKeycloak" clientId="XXXXXX" secret="XXXXXX" realm="XXXXXX" baseUri="XXXXXX" preferredJwsAlgorithmEnumId="OjaRS512"/>
		<roleMaps roleName="ADMIN" userGroupId="ADMIN" roleTypeId="Employee"/>
		<fieldMaps ruleSeqId="01" srcFieldName="name" dstFieldName="userFullName"/>
		<fieldMaps ruleSeqId="02" srcFieldName="given_name" dstFieldName="firstName"/>
		<fieldMaps ruleSeqId="03" srcFieldName="family_name" dstFieldName="lastName"/>
		<fieldMaps ruleSeqId="04" srcFieldName="email" dstFieldName="emailAddress"/>
	</moqui.security.sso.AuthFlow>

	<moqui.security.sso.AuthFlow authFlowId="GitHub" authFlowTypeEnumId="AftOauth" description="GitHub" defaultUserGroupId="ALL_USERS" sequenceNum="2" iconName="globe">
		<oauth clientTypeEnumId="OctGitHub" clientId="XXXXXX" secret="XXXXXX"/>
		<fieldMaps ruleSeqId="01" srcFieldName="name" dstFieldName="userFullName"/>
		<fieldMaps ruleSeqId="02" srcFieldName="login" dstFieldName="emailAddress" dstFieldExpression="login + '@moqui.org'"/>
		<fieldMaps ruleSeqId="03" srcFieldName="name" dstFieldName="firstName" dstFieldExpression="name.split(' ').length > 2 ? name.split(' ')[0] + ' ' + name.split(' ')[1] : name.split(' ')[0]"/>
		<fieldMaps ruleSeqId="04" srcFieldName="name" dstFieldName="lastName" dstFieldExpression="name.replaceFirst(name.split(' ').length > 2 ? name.split(' ')[0] + ' ' + name.split(' ')[1] : name.split(' ')[0], '').trim()"/>
	</moqui.security.sso.AuthFlow>

	<moqui.security.sso.AuthFlow authFlowId="Duo" authFlowTypeEnumId="AftSaml" description="Duo" defaultUserGroupId="ALL_USERS" sequenceNum="3" iconName="globe">
		<saml keystoreLocation="XXXXXX" keystorePassword="XXXXXX" privateKeyPassword="XXXXXX" serviceProviderEntityId="XXXXXX" identityProviderMetadataLocation="XXXXXX"/>
		<fieldMaps ruleSeqId="01" srcFieldName="Name" dstFieldName="userFullName" dstFieldTypeEnumId="DftString" dstFieldExpression="Name.get(0)"/>
		<fieldMaps ruleSeqId="02" srcFieldName="email" dstFieldName="emailAddress" dstFieldTypeEnumId="DftString"/>
		<fieldMaps ruleSeqId="03" srcFieldName="first_name" dstFieldName="firstName" dstFieldTypeEnumId="DftString"/>
		<fieldMaps ruleSeqId="04" srcFieldName="last_name" dstFieldName="lastName" dstFieldTypeEnumId="DftString"/>
	</moqui.security.sso.AuthFlow>
</entity-facade-xml>

Feel free to reach out to me with feedback or comments!

8 Likes

Great news, thanks. We will be checking it out in the next weeks.

1 Like

Awsome!Thanks for contribution!

1 Like

This is great. Thanks for doing this Ayman!

I was able to set it up with GitHub. For those that are interested in how, here’s a couple steps:

Setup Note: Before following Ayman’s steps ahead, you’ll need to update your git repo with the latest moqui-framework, and moqui-runtime. This will add the moqui-sso component to addons.xml in moqui-framework, and the necessary changes to moqui-runtime (i.e. the Login screen)

This is for testing locally

  1. Boot up moqui at http://localhost:8080 as usual for development
  2. Follow this Github tutorial to create an OAuth App: Creating an OAuth app - GitHub Docs
  3. Go to http://localhost:8080/qapps/tools/Entity/DataImport and import the following changed data (the changed data handles the scenario where the name is null):

Note: make sure that you use the client and secret from github from the tutorial in step 2 (see screenshot)

             <moqui.security.sso.AuthFlow defaultUserGroupId="ALL_USERS" sequenceNum="2" authFlowId="GitHub" iconName="globe" authFlowTypeEnumId="AftOauth" description="GitHub">
                <oauth clientId="ExampleClientId" secret="ExampleSecret" clientTypeEnumId="OctGitHub"/>
                <fieldMaps ruleSeqId="01" dstFieldName="userFullName" srcFieldName="name"/>
                <fieldMaps ruleSeqId="02" dstFieldName="emailAddress" srcFieldName="login" dstFieldExpression="login + '@moqui.org'"/>
                <fieldMaps ruleSeqId="03" dstFieldName="firstName" srcFieldName="name" dstFieldExpression="name?name.split(' ').length > 2 ? name.split(' ')[0] + ' ' + name.split(' ')[1] : name.split(' ')[0]:login"/>
                <fieldMaps ruleSeqId="04" dstFieldName="lastName" srcFieldName="name" dstFieldExpression="name?name.replaceFirst(name.split(' ').length > 2 ? name.split(' ')[0] + ' ' + name.split(' ')[1] : name.split(' ')[0], '').trim():login"/>
            </moqui.security.sso.AuthFlow>


4. Then go to http://localhost:8080/Login#sso and click Github

Note: For @aabiabdallah and those who try this out on a chromium browser. I was able to have it work just fine with firefox. However on a chromium browser, the 303 redirect for the /sso/Login endpoint form submit wasn’t allowed (see error below). Can someone please reproduce this?

Refused to send form data to 'http://localhost:8080/sso/login' because it violates the following Content Security Policy directive: "form-action 'self'".
1 Like

Minimum steps to taste SSO component.

  1. download SSO component from github, and re-build the moqui project.
  2. import all seed-data from SSO SecurityEntities.xml file
  3. download Login.ftl and webroot-layout.CSS locating under webroot dir of base-component.
  4. Goto github create a authapp, then copy the clientId and ClientSecret into :
<moqui.security.sso.AuthFlow defaultUserGroupId="ALL_USERS" sequenceNum="2" authFlowId="GitHub" iconName="globe" authFlowTypeEnumId="AftOauth" description="GitHub">
                <oauth clientId="ExampleClientId" secret="ExampleSecret" clientTypeEnumId="OctGitHub"/>
                <fieldMaps ruleSeqId="01" dstFieldName="userFullName" srcFieldName="name"/>
                <fieldMaps ruleSeqId="02" dstFieldName="emailAddress" srcFieldName="login" dstFieldExpression="login + '@moqui.org'"/>
                <fieldMaps ruleSeqId="03" dstFieldName="firstName" srcFieldName="name" dstFieldExpression="name?name.split(' ').length > 2 ? name.split(' ')[0] + ' ' + name.split(' ')[1] : name.split(' ')[0]:login"/>
                <fieldMaps ruleSeqId="04" dstFieldName="lastName" srcFieldName="name" dstFieldExpression="name?name.replaceFirst(name.split(' ').length > 2 ? name.split(' ')[0] + ' ' + name.split(' ')[1] : name.split(' ')[0], '').trim():login"/>
            </moqui.security.sso.AuthFlow>

as @michael mentioned in his post.

then import it.

  1. then Logout and goto login page under http://localhost:8080/apps, it will jump to login page under webroot.

  2. then click github button .
    1702735207388

1702735134317

Yes, I reproduced the Refused error.
That is becuase you have a

<meta http-equiv="Content-Security-Policy"  />

somewhere defined in the html head section. If you remove this definition, it will redirect smoothly to Github. Or you can add Github to this definition

Hope it helps.

Have you noticed the error when trying to use LinkedIn Sign In with LinkedIn using OpenID Connect
I got the following error:

--- 2024-02-13 03:44:03.776 [qtp872826668-29] ERROR            org.moqui.impl.context.LoggerFacadeImpl [] []
 An error occurred while handling callback
*org.pac4j.core.exception.TechnicalException: Bad token response, error=invalid_request, description=A required parameter client_secret is missing*
	at org.pac4j.oidc.credentials.authenticator.OidcAuthenticator.executeTokenRequest(OidcAuthenticator.java:206) ~[pac4j-oidc-5.7.1.jar:?]
	at org.pac4j.oidc.credentials.authenticator.OidcAuthenticator.validate(OidcAuthenticator.java:165) ~[pac4j-oidc-5.7.1.jar:?]
	at org.pac4j.core.client.BaseClient.lambda$retrieveCredentials$0(BaseClient.java:75) ~[pac4j-core-5.7.1.jar:?]
	at java.util.Optional.ifPresent(Optional.java:183) ~[?:?]
	at org.pac4j.core.client.BaseClient.retrieveCredentials(BaseClient.java:72) ~[pac4j-core-5.7.1.jar:?]
	at org.pac4j.core.client.IndirectClient.getCredentials(IndirectClient.java:145) ~[pac4j-core-5.7.1.jar:?]
	at org.pac4j.core.engine.DefaultCallbackLogic.perform(DefaultCallbackLogic.java:75) ~[pac4j-core-5.7.1.jar:?]
	at org.pac4j.core.engine.CallbackLogic$perform.call(Unknown Source) ~[?:?]
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47) ~[moqui_temp10653206240214054500WEB-INF_lib_groovy-3.0.9.jar.:3.0.9]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125) ~[moqui_temp10653206240214054500WEB-INF_lib_groovy-3.0.9.jar.:3.0.9]
	at org.moqui.sso.AuthenticationFlow.handleCallback(AuthenticationFlow.groovy:87) ~[moqui-sso-1.0.0.jar:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
	at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
	at org.moqui.impl.service.runner.JavaServiceRunner.runService(JavaServiceRunner.groovy:66) ~[moqui_temp13016124410341027508WEB-INF_lib_moqui-framework-3.0.0.jar.:3.0.0]
	at org.moqui.impl.service.ServiceCallSyncImpl.callSingle(ServiceCallSyncImpl.java:322) ~[moqui_temp13016124410341027508WEB-INF_lib_moqui-framework-3.0.0.jar.:3.0.0]
	at org.moqui.impl.service.ServiceCallSyncImpl.call(ServiceCallSyncImpl.java:125) ~[moqui_temp13016124410341027508WEB-INF_lib_moqui-framework-3.0.0.jar.:3.0.0]
	at org.moqui.service.ServiceCallSync$call$0.call(Unknown Source) ~[?:?]
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47) ~[moqui_temp10653206240214054500WEB-INF_lib_groovy-3.0.9.jar.:3.0.9]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125) ~[moqui_temp10653206240214054500WEB-INF_lib_groovy-3.0.9.jar.:3.0.9]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:130) ~[moqui_temp10653206240214054500WEB-INF_lib_groovy-3.0.9.jar.:3.0.9]
	at component___moqui_sso_screen_sso_xml_transition_callback_actions.run(component___moqui_sso_screen_sso_xml_transition_callback_actions:11) ~[?:?]
	at org.moqui.impl.actions.XmlAction.run(XmlAction.java:67) ~[moqui_temp13016124410341027508WEB-INF_lib_moqui-framework-3.0.0.jar.:3.0.0]
	at org.moqui.impl.screen.ScreenDefinition$TransitionItem.run(ScreenDefinition.groovy:987) ~[moqui_temp13016124410341027508WEB-INF_lib_moqui-framework-3.0.0.jar.:3.0.0]
	at org.moqui.impl.screen.ScreenRenderImpl.recursiveRunTransition(ScreenRenderImpl.groovy:757) ~[moqui_temp13016124410341027508WEB-INF_lib_moqui-framework-3.0.0.jar.:3.0.0]
	at org.moqui.impl.screen.ScreenRenderImpl.recursiveRunTransition(ScreenRenderImpl.groovy:753) ~[moqui_temp13016124410341027508WEB-INF_lib_moqui-framework-3.0.0.jar.:3.0.0]
	at org.moqui.impl.screen.ScreenRenderImpl.internalRender(ScreenRenderImpl.groovy:454) ~[moqui_temp13016124410341027508WEB-INF_lib_moqui-framework-3.0.0.jar.:3.0.0]
	at org.moqui.impl.screen.ScreenRenderImpl.render(ScreenRenderImpl.groovy:170) ~[moqui_temp13016124410341027508WEB-INF_lib_moqui-framework-3.0.0.jar.:3.0.0]
	at org.moqui.impl.webapp.MoquiServlet.service(MoquiServlet.groovy:118) ~[moqui_temp13016124410341027508WEB-INF_lib_moqui-framework-3.0.0.jar.:3.0.0]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:750) ~[moqui.war:3.0.0]
	at org.eclipse.jetty.servlet.ServletHolder$NotAsync.service(ServletHolder.java:1410) ~[moqui_temp14844224054252611520execlib_jetty-servlet-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:764) ~[moqui_temp14844224054252611520execlib_jetty-servlet-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1630) ~[moqui_temp14844224054252611520execlib_jetty-servlet-10.0.9.jar.:10.0.9]
	at HostCleanFilter.doFilter(HostCleanFilter.java:225) ~[moqui.war:?]
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:202) ~[moqui_temp14844224054252611520execlib_jetty-servlet-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1600) ~[moqui_temp14844224054252611520execlib_jetty-servlet-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:170) ~[moqui_temp33892897111477974execlib_websocket-servlet-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:202) ~[moqui_temp14844224054252611520execlib_jetty-servlet-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1600) ~[moqui_temp14844224054252611520execlib_jetty-servlet-10.0.9.jar.:10.0.9]
	at org.moqui.impl.webapp.ElasticRequestLogFilter.doFilter(ElasticRequestLogFilter.groovy:110) ~[moqui_temp13016124410341027508WEB-INF_lib_moqui-framework-3.0.0.jar.:3.0.0]
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:202) ~[moqui_temp14844224054252611520execlib_jetty-servlet-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1600) ~[moqui_temp14844224054252611520execlib_jetty-servlet-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:506) ~[moqui_temp14844224054252611520execlib_jetty-servlet-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:131) ~[moqui_temp8753752083419951429execlib_jetty-server-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:578) ~[moqui_temp16966687951898033334execlib_jetty-security-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122) ~[moqui_temp8753752083419951429execlib_jetty-server-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:223) ~[moqui_temp8753752083419951429execlib_jetty-server-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1571) ~[moqui_temp8753752083419951429execlib_jetty-server-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:221) ~[moqui_temp8753752083419951429execlib_jetty-server-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1378) ~[moqui_temp8753752083419951429execlib_jetty-server-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:176) ~[moqui_temp8753752083419951429execlib_jetty-server-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:463) ~[moqui_temp14844224054252611520execlib_jetty-servlet-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1544) ~[moqui_temp8753752083419951429execlib_jetty-server-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:174) ~[moqui_temp8753752083419951429execlib_jetty-server-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1300) ~[moqui_temp8753752083419951429execlib_jetty-server-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:129) ~[moqui_temp8753752083419951429execlib_jetty-server-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:717) ~[moqui_temp8753752083419951429execlib_jetty-server-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122) ~[moqui_temp8753752083419951429execlib_jetty-server-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.server.Server.handle(Server.java:562) ~[moqui_temp8753752083419951429execlib_jetty-server-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.server.HttpChannel.lambda$handle$0(HttpChannel.java:505) ~[moqui_temp8753752083419951429execlib_jetty-server-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:762) ~[moqui_temp8753752083419951429execlib_jetty-server-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:497) ~[moqui_temp8753752083419951429execlib_jetty-server-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:282) ~[moqui_temp8753752083419951429execlib_jetty-server-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:319) ~[moqui_temp7075068661577100833WEB-INF_lib_jetty-io-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:100) ~[moqui_temp7075068661577100833WEB-INF_lib_jetty-io-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53) ~[moqui_temp7075068661577100833WEB-INF_lib_jetty-io-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:412) ~[moqui_temp3153816534271096162WEB-INF_lib_jetty-util-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:381) ~[moqui_temp3153816534271096162WEB-INF_lib_jetty-util-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:268) ~[moqui_temp3153816534271096162WEB-INF_lib_jetty-util-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.lambda$new$0(AdaptiveExecutionStrategy.java:138) ~[moqui_temp3153816534271096162WEB-INF_lib_jetty-util-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:407) ~[moqui_temp3153816534271096162WEB-INF_lib_jetty-util-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:894) ~[moqui_temp3153816534271096162WEB-INF_lib_jetty-util-10.0.9.jar.:10.0.9]
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1038) ~[moqui_temp3153816534271096162WEB-INF_lib_jetty-util-10.0.9.jar.:10.0.9]
	at java.lang.Thread.run(Thread.java:829) ~[?:?]
--- 2024-02-13 03:44:03.794 [qtp872826668-29] ERROR                 org.moqui.impl.webapp.MoquiServlet [] []
 Internal error processing request: java.lang.IllegalStateException: Committed
java.lang.IllegalStateException: Committed

It seems that the pac4j code does not set client secret properly. login#user seems fine. Only error in handdleCalback

1 Like

Hi Strand,

The OOTB support for LinkedIn is via OAuth. I see you’re using the OIDC end point in your log. Which client did you use for this (i.e. clientTypeEnumId)?

1 Like

OctLinkedIn is what I am using. authFlowTypeEnumId="AftOidc" and with OidcFlow entity.
Should I use ClientType with OctOther? LinkedIn now is deprecating the old Oauth, starting using openid connection.

https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/sign-in-with-linkedin-v2?context=linkedin%2Fconsumer%2Fcontext

1 Like

Reply to myself.

The linkedIn openid connection is kind of oauth2. The pac4j package OctLinkedIn client is based on oauth1. Thus not working with LinkedIn openid connection.

Working smoothly with Github and x(twitter). Just remember for Twitter, not use clientId and client secret, it has to be api key and corresponding secret.

Thanks to @aabiabdallah for a excellent sso component.

1 Like

If somebody will use this sso component for Google Auth2, remember the redirect uri setup in Google cloud console has to be https://yourDomainName.com/sso/callback?client_name=Google . The important part is ?client_name=Google as pac4j Goolge2Client will append this to the end of the callback url. If not present, Google will comoplain the uri_dismatch or something like this.

And with Google Aouth2, the Profile will not return the valid username, thus a proper username has to be created by using profile’s id or email field value.

1 Like