Question Is it possible for a back-end-web-app to accept and pick up the user identity from the AAD authentication cookie generated by signing in to a front-end-web-app?
Background I want to achieve an Azure Active Directory single sign on experience for a JavaScript SignalR client but my current solution requires the user to sign in twice. Once to access the web app hosting the js-client and then again so that the js-client-app can access the back-end.
Desired solution with SSO AAD Authentication
- Front-end (OWIN/MVC/JavaScript)
- AAD authentication to identify the user - implemented
- JS SignalR client includes the auth cookie in the server requests - works by default
- Back-end (OWIN/SignalR PersistentConnection)
- Identify the user via the the encrypted .AspNetCookies cookie from the front-end authentication that is included in the SignalR requests.
- the cookie is not accepted and the debug output from OWIN is Microsoft.Owin.Security.Cookies.CookieAuthenticationMiddleware Warning: 0 : Unprotect ticket failed
Attempted Back-End Startup.cs
public void ConfigureAuth( IAppBuilder app )
app.SetDefaultSignInAsAuthenticationType( CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
RedirectUri = redirectUri,
PostLogoutRedirectUri = redirectUri,
TokenValidationParameters = new TokenValidationParameters
{
RoleClaimType = "roles"
}
});
}
Current solution with undesirable dual sign in
- Front-end web app (OWIN/MVC/JavaScript)
- Owin handles AAD authentication
- MVC generates views based on the authenticated user
- ADAL JS handles user authentication client-side and acquires an access token that is added as a cookie (my_access_token)
- Back-end web app (OWIN/SignalR PersistentConnection)
- OWIN handles authentication by extracting the access token found in the my-_access_token cookie and adding it as a Bearer Authorization header
- Authorization is handled by overriding the Authorize function in PersistentConnection based on the authenticated user
Current Front-End Startup.cs
public void ConfigureAuth( IAppBuilder app )
GlobalFilters.Filters.Add( new AuthorizeAttribute() );
app.SetDefaultSignInAsAuthenticationType( CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
RedirectUri = redirectUri,
PostLogoutRedirectUri = redirectUri,
TokenValidationParameters = new TokenValidationParameters
{
RoleClaimType = "roles"
}
});
}
Current Back-end Startup.cs
public void Configuration( IAppBuilder app ){
app.Use( ( context, next ) =>
{
if (context.Request.Cookies.Any(c => c.Key.Equals("BearerToken")))
{
var cookie = context.Request.Cookies.First(c => c.Key.Equals("BearerToken"));
context.Request.Headers.Add("Authorization", new[] { $"Bearer {cookie.Value}" });
}
return next.Invoke();
});
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = tenant,
TokenValidationParameters = new TokenValidationParameters
{
ValidAudience = audience,
RoleClaimType = "roles"
}
};
);
}