Generate JWT token for an active directory user that has already authenticated using cookies

Viewed 17

I have the following setup:

  • Application A:
    • runs .net framework 4.6.1
    • serves Angular application and API
    • authenticate users using cookies
    • authentification is done using OpenIdConnect and Active Directory (see implementation of Startup.cs below)
  • Application B:
    • runs on .net 6.0
    • serves a SignalR endpoint

I would like application B usage to be restricted only to users authenticated on app A (as app A is the only way to use app B). From what I understood, the recommended way of doing this is to use a JWT token in application B. However, I don't know how to generate this JWT token so that users don't have to authenticate again.

So far, I have tried to authenticate users in app B using the cookies created in app A that are to app B (since they are on the same domain name) but this does not work (as I guess that the server does not have the session state). I also tried to get the access_token using

var token = Request.GetOwinContext().Authentication.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationType).Properties.Dictionary["access_token"];

But the key does not exist in the dictionary.

Any help or hint would be greatly appreciated. Thank you !

    /// <summary>
    /// Startup class
    /// </summary>
    public partial class Startup
    {
        #region OpenIDConnect settings

        // The Client ID is used by the application to uniquely identify itself to Azure AD.
        string clientId = ConfigurationManager.AppSettings["ida:ClientId"];

        // RedirectUri is the URL where the user will be redirected to after they sign in.
        string redirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];

        // Tenant is the tenant ID (e.g. contoso.onmicrosoft.com, or 'common' for multi-tenant)
        static string tenant = ConfigurationManager.AppSettings["ida:Tenant"];

        // Authority is the URL for authority, composed by Microsoft identity platform endpoint and the tenant name
        string authority = string.Format(CultureInfo.InvariantCulture, ConfigurationManager.AppSettings["ida:Authority"], tenant);

        #endregion

        #region Cookies Authentication settings

        string cookieName = ConfigurationManager.AppSettings["cookies:Name"];
        string cookieNameLegacy = ConfigurationManager.AppSettings["cookies:NameLegacy"];
        string cookieDomain = ConfigurationManager.AppSettings["cookies:Domain"];
        string logoutPath = ConfigurationManager.AppSettings["cookies:LogoutPath"];

        #endregion


        /// <summary>
        /// OAuth authorization server options
        /// </summary>
        public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }

        /// <summary>
        /// Public Client Id
        /// </summary>
        public static string PublicClientId { get; private set; }

        /// <summary>
        /// Configure OWIN to use OAuth and OpenIdConnect
        /// </summary>
        /// <param name="app"></param>
        public void ConfigureAuth(IAppBuilder app)
        {
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

            var cookieAuthenticationOptions = new CookieAuthenticationOptions
            {
                CookieName = cookieName,
                SlidingExpiration = true,
                CookieDomain = cookieDomain,
                LogoutPath = new PathString(logoutPath)
            };
            app.UseCookieAuthentication(cookieAuthenticationOptions);

            var legacyCookieOptions = new LegacyCookiesOptions
            {
                CookieName = cookieNameLegacy
            };
            app.UseLegacyCookieAuthentication(legacyCookieOptions);

            var openIdConnectAuthenticationOptions = new OpenIdConnectAuthenticationOptions
            {
                ClientId = clientId,
                Authority = authority,
                RedirectUri = redirectUri,
                PostLogoutRedirectUri = redirectUri,
                UseTokenLifetime = true,   /*False in production*/
                SaveTokens = true,
                RedeemCode = true,


                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    AuthenticationFailed = OnAuthenticationFailed,
                    SecurityTokenValidated = OnSecurityTokenValidated,
                    RedirectToIdentityProvider = OnRedirectToIdentityProvider
                }
            };

            app.UseOpenIdConnectAuthentication(openIdConnectAuthenticationOptions);

            app.UseClaimsTransformation(claimsPrincipal =>
            {
                // either add claims to incoming, or create new principal
                var claims = new ClaimsPrincipal(claimsPrincipal);
                AuthHelper.UpdateClaimName(claimsPrincipal.Identities.First());
                return Task.FromResult(claims);
            });

            // This makes any middleware defined above this line run before the Authorization rule is applied in web.config
            app.UseStageMarker(PipelineStage.Authenticate);


            // Configure the application for OAuth based flow
            PublicClientId = "self";
            OAuthOptions = new OAuthAuthorizationServerOptions
            {
                TokenEndpointPath = new PathString("/api/auth/token"),
                Provider = new ApplicationOAuthProvider(PublicClientId),
                AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
                // In production mode set AllowInsecureHttp = false
                AllowInsecureHttp = true
            };

            // Enable the application to use bearer tokens to authenticate users
            app.UseOAuthBearerTokens(OAuthOptions);
        }


        private Task OnRedirectToIdentityProvider(RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
        {
            context.ProtocolMessage.DomainHint = "medpace.com";

            string url = context.Request.Uri.GetLeftPart(UriPartial.Path);
            bool IsSkipLogin = url.Contains("ForceAuthenticate.aspx") && context.OwinContext.Authentication.User.Identity.IsAuthenticated;

            if (IsSkipLogin == false)
            {
                context.ProtocolMessage.Prompt = "login";
            }

            return Task.FromResult(0);
        }

        /// <summary>
        /// Records the failed logon attempt
        /// </summary>
        /// <param name="context">Authentication failed notification context</param>
        /// <returns></returns>
        private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
        {
            var claims = context?.OwinContext?.Authentication?.User?.Identity as ClaimsIdentity;
            var accountId = claims?.Name ?? string.Empty;
            var remoteIpAddress = AuthHelper.GetRemoteIpAddress(claims);

            //AddLogonAttempt(accountId, remoteIpAddress);

            if (context.Exception is OpenIdConnectProtocolInvalidNonceException)
            {
                if (context.Exception.Message.Contains("IDX10311"))
                {
                    context.SkipToNextMiddleware();
                }
            }

            return Task.FromResult(0);
        }

        /// <summary>
        /// Adds claims and record the successful logon attempt
        /// </summary>
        /// <param name="context">Security token validated notification</param>
        /// <returns></returns>
        private Task OnSecurityTokenValidated(SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
        {
            context.AuthenticationTicket.Properties.AllowRefresh = true;

            var idToken = context.ProtocolMessage.IdToken;
            var claims = context.AuthenticationTicket.Identity;

            var accountId = AuthHelper.UpdateClaimsIdentity(claims, idToken);
            var remoteIpAddress = AuthHelper.GetRemoteIpAddress(claims);

            return Task.FromResult(0);
        }
0 Answers
Related