<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="https://shazwazza.com/rss/xslt"?>
<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title>Shazwazza</title>
    <link>https://shazwazza.com/</link>
    <description>My blog which is pretty much just all about coding</description>
    <generator>Articulate, blogging built on Umbraco</generator>
    <image>
      <url>/media/0libq25y/frog.png?rmode=max&amp;v=1da0e911f4e6890</url>
      <title>Shazwazza</title>
      <link>https://shazwazza.com/</link>
    </image>
    <item>
      <guid isPermaLink="false">1278</guid>
      <link>https://shazwazza.com/post/configuring-aspnet-identity-oauth-login-providers-for-multi-tenancy/</link>
      <category>ASP.Net</category>
      <title>Configuring ASP.Net Identity OAuth login providers for multi-tenancy</title>
      <description>&lt;p&gt;Say for example you have a CMS :) You want to give full control to the developer to manage how their front-end members with authenticate, which could of course include ASP.Net Identity OAuth login providers. At the same time you want to easily allow your CMS to be configured so that ASP.Net Identity OAuth providers can be used for logging into the back office.&amp;nbsp; In this scenario, the same OAuth provider might be used for both front-end and back-office authentication but authenticated under 2 different OAuth accounts. Another example might be if you have multi-tenancy set up for your front-end site and perhaps you want to use the same OAuth login provider but have members authenticate with different OAuth accounts for different domain names. &lt;/p&gt; &lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;  &lt;h2&gt;The defaults&lt;/h2&gt; &lt;p&gt;As an example, lets assume that front-end members are configured to authenticate with the ASP.Net Identity Google OAuth2 provider. This is easily done by just following one of the many tutorials out there. Your startup code might look like:&lt;/p&gt;&lt;pre class="csharpcode"&gt;app.UseCookieAuthentication(&lt;span class="kwrd"&gt;new&lt;/span&gt; CookieAuthenticationOptions ....

app.UseExternalSignInCookie();

app.UseGoogleAuthentication(
              clientId: &lt;span class="str"&gt;"123456789..."&lt;/span&gt;,
              clientSecret: &lt;span class="str"&gt;"987654321...."&lt;/span&gt;);&lt;/pre&gt;
&lt;p&gt;Great, but I need 2 (or more) Google OAuth2 providers, so what now? I can’t just add 2 declarations of:&lt;/p&gt;&lt;pre class="csharpcode"&gt;app.UseGoogleAuthentication(
              clientId: &lt;span class="str"&gt;"123456789..."&lt;/span&gt;,
              clientSecret: &lt;span class="str"&gt;"987654321...."&lt;/span&gt;);

app.UseGoogleAuthentication(
              clientId: &lt;span class="str"&gt;"abcdef..."&lt;/span&gt;,
              clientSecret: &lt;span class="str"&gt;"zyxwv...."&lt;/span&gt;);&lt;/pre&gt;
&lt;p&gt;you’ll quickly realize that doesn’t work and only one provider instance will actually be used. This is because of the default underlying settings that get used to instantiate the Google provider. Let’s have a look at what the default options are in this case. The above code is equivalent to this:&lt;/p&gt;&lt;pre class="csharpcode"&gt;app.UseGoogleAuthentication(&lt;span class="kwrd"&gt;new&lt;/span&gt; GoogleOAuth2AuthenticationOptions
{
    AuthenticationType = &lt;span class="str"&gt;"Google"&lt;/span&gt;,
    ClientId = &lt;span class="str"&gt;"123456789..."&lt;/span&gt;,
    ClientSecret = &lt;span class="str"&gt;"987654321...."&lt;/span&gt;,
    Caption = &lt;span class="str"&gt;"Google"&lt;/span&gt;,
    CallbackPath = &lt;span class="kwrd"&gt;new&lt;/span&gt; PathString(&lt;span class="str"&gt;"/signin-google"&lt;/span&gt;),
    AuthenticationMode = AuthenticationMode.Passive,
    SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(),
    BackchannelTimeout = TimeSpan.FromSeconds(60),
    BackchannelHttpHandler = &lt;span class="kwrd"&gt;new&lt;/span&gt; System.Net.Http.WebRequestHandler(),
    BackchannelCertificateValidator = &lt;span class="kwrd"&gt;null&lt;/span&gt;,
    Provider = &lt;span class="kwrd"&gt;new&lt;/span&gt; GoogleOAuth2AuthenticationProvider()
});&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;h2&gt;The AuthenticationType&lt;/h2&gt;
&lt;p&gt;One very important aspect of the default settings is the &lt;em&gt;AuthenticationType&lt;/em&gt;. This is a &lt;strong&gt;unique &lt;/strong&gt;identifier for the provider instance and this is one of the reasons why if you have 2 x &lt;em&gt;UseGoogleAuthentication&lt;/em&gt; declarations with the defaults only one will ever be used.&lt;/p&gt;
&lt;p&gt;Knowing this, it’s clear that each declaration of &lt;em&gt;UseGoogleAuthentication&lt;/em&gt; needs to specify custom options and have the &lt;em&gt;AuthenticationType&lt;/em&gt; unique amongst them. So we might end up with something like:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;//keep defaults for front-end&lt;/span&gt;
app.UseGoogleAuthentication(
    clientId: &lt;span class="str"&gt;"123456789..."&lt;/span&gt;,
    clientSecret: &lt;span class="str"&gt;"987654321...."&lt;/span&gt;);

&lt;span class="rem"&gt;//custom options for back-office&lt;/span&gt;
app.UseGoogleAuthentication(&lt;span class="kwrd"&gt;new&lt;/span&gt; GoogleOAuth2AuthenticationOptions
{
    AuthenticationType = &lt;span class="str"&gt;"GoogleBackOffice"&lt;/span&gt;,
    ClientId = &lt;span class="str"&gt;"abcdef..."&lt;/span&gt;,
    ClientSecret = &lt;span class="str"&gt;"zyxwv...."&lt;/span&gt;    
});&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;If you test this now, you’ll find out that only the first declaration is actually working even when you explicitly tell &lt;em&gt;IOwinContext.Authentication.Challenge&lt;/em&gt; to use the “GoogleBackOffice” provider.&lt;/p&gt;
&lt;h2&gt;The CallbackPath&lt;/h2&gt;
&lt;p&gt;The reason that the default (first) declaration is the one that activates is because the response from Google is sending the request to the path: “/signin-google”, which is the default. The &lt;em&gt;GoogleAuthenticationMiddleware &lt;/em&gt;will delegate to the &lt;em&gt;GoogleAuthenticationHandler &lt;/em&gt;for each request and inspect the request to see if it should execute. For this logic it checks: &lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (Options.CallbackPath.HasValue &amp;amp;&amp;amp; Options.CallbackPath == Request.Path)
{
     &lt;span class="rem"&gt;//If the path matches, auth the request...&lt;/span&gt;
}&lt;/pre&gt;
&lt;p&gt;Since the &lt;em&gt;CallbackPath&lt;/em&gt; will be the same by default on both above declarations, the first one that is registered will match and the other registered authenticators will be ignored. To fix this we’ll need to update the path that Google sends back and then update the second declaration to match that path. &lt;/p&gt;
&lt;p&gt;To tell Google to send the request back on a different path, in your Google Developers Console change the REDIRECT URIS value for the second provider:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://shazwazza.com/media/articulate/windows-live-writer-connet-identity-oauth-login-providers-f_a1ef-image_thumb_2.png"&gt;&lt;img title="image_thumb" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image_thumb" src="http://shazwazza.com/media/articulate/windows-live-writer-connet-identity-oauth-login-providers-f_a1ef-image_thumb_thumb.png" width="244" height="216"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Then we need to update the 2nd declaration with the custom &lt;em&gt;CallbackPath&lt;/em&gt; so that it matches and activates properly:&lt;/p&gt;&lt;pre class="csharpcode"&gt;app.UseGoogleAuthentication(&lt;span class="kwrd"&gt;new&lt;/span&gt; GoogleOAuth2AuthenticationOptions
{
    AuthenticationType = &lt;span class="str"&gt;"GoogleBackOffice"&lt;/span&gt;,
    ClientId = &lt;span class="str"&gt;"abcdef..."&lt;/span&gt;,
    ClientSecret = &lt;span class="str"&gt;"zyxwv...."&lt;/span&gt;,
    CallbackPath = &lt;span class="kwrd"&gt;new&lt;/span&gt; PathString(&lt;span class="str"&gt;"/custom-signin-google"&lt;/span&gt;)
});&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;Hooray, now it should work!&lt;/p&gt;
&lt;p&gt;This concept is the same for most external login providers. For example for the Facebook one the default value is “/signin-facebook”, you’d need to configure Facebook’s “Valid OAuth redirect URIs” property with the correct callback path in Facebook’s developer portal:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://shazwazza.com/media/articulate/windows-live-writer-connet-identity-oauth-login-providers-f_a1ef-image_thumb1_2.png"&gt;&lt;img title="image_thumb1" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image_thumb1" src="http://shazwazza.com/media/articulate/windows-live-writer-connet-identity-oauth-login-providers-f_a1ef-image_thumb1_thumb.png" width="184" height="244"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;What is SignInAsAuthenticationType?&lt;/h2&gt;
&lt;p&gt;The last thing to point out is that by default the &lt;em&gt;SignInAsAuthenticationType &lt;/em&gt;for each provider will resolve to: &lt;em&gt;app.GetDefaultSignInAsAuthenticationType()&lt;/em&gt;, which by default is: &lt;em&gt;DefaultAuthenticationTypes.ExternalCookie&lt;/em&gt;&amp;nbsp; = “ExternalCookie”. Each OAuth provider is linked to another middleware that is responsible for actually issuing a user’s ClaimsIdentity, so by default this will be “ExternalCookie”. In some cases you won’t want the default external cookie authentication middleware to assign the ClaimsIdentity for your OAuth provider, you might need to issue a different ClaimsIdentity or just have more granular control over what happens with the callback for each OAuth provider. In this case you’ll need to specify another custom cookie authentication declaration, for example:&lt;/p&gt;&lt;pre class="csharpcode"&gt;app.UseCookieAuthentication(&lt;span class="kwrd"&gt;new&lt;/span&gt; CookieAuthenticationOptions
{
    AuthenticationType = &lt;span class="str"&gt;"CustomExternal"&lt;/span&gt;,
    AuthenticationMode = AuthenticationMode.Passive,
    CookieName = &lt;span class="str"&gt;"MyAwesomeCookie"&lt;/span&gt;,
    ExpireTimeSpan = TimeSpan.FromMinutes(5),
    &lt;span class="rem"&gt;//Additional custom cookie options....&lt;/span&gt;
});&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;And then you can link that up to your OAuth declaration like:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;//custom options for back-office&lt;/span&gt;
app.UseGoogleAuthentication(&lt;span class="kwrd"&gt;new&lt;/span&gt; GoogleOAuth2AuthenticationOptions
{
    AuthenticationType = &lt;span class="str"&gt;"GoogleBackOffice"&lt;/span&gt;,
    ClientId = &lt;span class="str"&gt;"abcdef..."&lt;/span&gt;,
    ClientSecret = &lt;span class="str"&gt;"zyxwv...."&lt;/span&gt;,
    SignInAsAuthenticationType = &lt;span class="str"&gt;"CustomExternal"&lt;/span&gt;
});&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:15 Z</pubDate>
      <a10:updated>2023-03-23T15:08:15Z</a10:updated>
    </item>
  </channel>
</rss>