2

I want to implement Azure authentication for my WebForms using OAuth (It is working for me). After authentication I required token for validate in server side and it will validate in every client code. But I am not getting Token after authentication

I have created a startup class and configure it using owin and it authenticating correctly but not able to get the token after authentication.

Startup class

using Microsoft.Owin;
using Owin;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Microsoft.Owin.Security.Notifications;
using System;
using System.Threading.Tasks;

[assembly: OwinStartup(typeof(Manager.Startup))]

namespace Manager
{
    public class Startup
    {
        // The Client ID is used by the application to uniquely identify itself to Azure AD.
        string clientId = System.Configuration.ConfigurationManager.AppSettings["ClientId"];

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

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

        // Authority is the URL for authority, composed by Azure Active Directory v2 endpoint and the tenant name (e.g. https://login.microsoftonline.com/contoso.onmicrosoft.com/v2.0)
        string authority = String.Format(System.Globalization.CultureInfo.InvariantCulture, System.Configuration.ConfigurationManager.AppSettings["Authority"], tenant);

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

            app.UseCookieAuthentication(new CookieAuthenticationOptions());
            app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                // Sets the ClientId, authority, RedirectUri as obtained from web.config
                ClientId = clientId,
                    Authority = authority,
                    RedirectUri = redirectUri,
                // PostLogoutRedirectUri is the page that users will be redirected to after sign-out. In this case, it is using the home page
                PostLogoutRedirectUri = redirectUri,
                    Scope = OpenIdConnectScope.OpenIdProfile,
                // ResponseType is set to request the id_token - which contains basic information about the signed-in user
                ResponseType = OpenIdConnectResponseType.IdToken,
                // ValidateIssuer set to false to allow personal and work accounts from any organization to sign in to your application
                // To only allow users from a single organizations, set ValidateIssuer to true and 'tenant' setting in web.config to the tenant name
                // To allow users from only a list of specific organizations, set ValidateIssuer to true and use ValidIssuers parameter 
                TokenValidationParameters = new TokenValidationParameters()
                    {
                        ValidateIssuer = false
                    },
                // OpenIdConnectAuthenticationNotifications configures OWIN to send notification of failed authentications to OnAuthenticationFailed method
                Notifications = new OpenIdConnectAuthenticationNotifications
                    {
                        AuthenticationFailed = OnAuthenticationFailed
                    }
                }
            );
        }

        /// <summary>
        /// Handle failed authentication requests by redirecting the user to the home page with an error in the query string
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
        {
            context.HandleResponse();
            context.Response.Redirect("/?errormessage=" + context.Exception.Message);
            return Task.FromResult(0);
        }
    }
}

on page load

 protected void Page_Load(object sender, EventArgs e)
        {
            if (!Request.IsAuthenticated)
            {
                Context.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = "/" },
        OpenIdConnectAuthenticationDefaults.AuthenticationType);

// below codes are tested but all are giving null or empty string 

                var claimsIdentity = User.Identity as ClaimsIdentity;
                string str = claimsIdentity?.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value;
                string accessToken = claimsIdentity?.Claims.FirstOrDefault(c => c.Type == "access_token")?.Value;
                string idToken = claimsIdentity?.Claims.FirstOrDefault(c => c.Type == "id_token")?.Value;
                string refreshToken = claimsIdentity?.Claims.FirstOrDefault(c => c.Type == "refresh_token")?.Value;
                str = User.Identity.Name;
                GetTokenForApplication().Wait(); ;
            }

        }

Expected result is Token after authentication Actual result is not getting token after authentication

1

2 Answers 2

0

The token won't contain in the claimsIdentity. To acquire the access token in the asp.net with OpenIdConnect protocol. You need to override the AuthorizationCodeReceived method to get the access token.

using System;
using System.Configuration;
using System.Threading.Tasks;
using Microsoft.Owin;
using Owin;
using Microsoft.IdentityModel.Protocols;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Microsoft.Owin.Security.Notifications;
using System.IdentityModel.Claims;
using ToDoGraphDemo.TokenStorage;
using System.Web;
using Microsoft.Identity.Client;

[assembly: OwinStartup(typeof(ToDoGraphDemo.Startup))]

namespace ToDoGraphDemo
{
    public class Startup
    {
        // The Client ID is used by the application to uniquely identify itself to Azure AD.
        string clientId = ConfigurationManager.AppSettings["ClientId"];
        // RedirectUri is the URL where the user will be redirected to after they sign in.
        string redirectUri = ConfigurationManager.AppSettings["RedirectUri"];
        // Tenant is the tenant ID (e.g. contoso.onmicrosoft.com, or 'common' for multi-tenant)
        static string tenant = ConfigurationManager.AppSettings["Tenant"];
        // Authority is the URL for authority, composed by Azure Active Directory v2 endpoint 
        // and the tenant name (e.g. https://login.microsoftonline.com/contoso.onmicrosoft.com/v2.0)
        string authority = String.Format(System.Globalization.CultureInfo.InvariantCulture, 
            ConfigurationManager.AppSettings["Authority"], tenant);
        // Scopes are the specific permissions we are requesting for the application.
        string scopes = ConfigurationManager.AppSettings["Scopes"];
        // ClientSecret is a password associated with the application in the authority. 
        // It is used to obtain an access token for the user on server-side apps.
        string clientSecret = ConfigurationManager.AppSettings["ClientSecret"];

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

            app.UseCookieAuthentication(new CookieAuthenticationOptions());
            app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
            {
                ClientId = clientId,
                Authority = authority,
                RedirectUri = redirectUri,
                PostLogoutRedirectUri = redirectUri,
                Scope = "openid email profile offline_access " + scopes,

                // TokenValidationParameters allows you to control the users who are allowed to sign in
                // to your application. In this demo we only allow users associated with the specified tenant. 
                // If ValidateIssuer is set to false, anybody with a personal or work Microsoft account can 
                // sign in.
                TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters()
                {
                    ValidateIssuer = true,
                    ValidIssuer = tenant
                },

                // OpenIdConnect event handlers/callbacks.
                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    AuthorizationCodeReceived = OnAuthorizationCodeReceived,
                    AuthenticationFailed = OnAuthenticationFailed
                }
            });
        }

        /// <summary>
        /// Handle authorization codes by creating a token cache then requesting and storing an access token
        /// for the user.
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification context)
        {
            string userId = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
            TokenCache userTokenCache = new SessionTokenCache(
                userId, context.OwinContext.Environment["System.Web.HttpContextBase"] as HttpContextBase).GetMsalCacheInstance();
            // A ConfidentialClientApplication is a server-side client application that can securely store a client secret,
            // which is not accessible by the user.
            ConfidentialClientApplication cca = new ConfidentialClientApplication(
                clientId, redirectUri, new ClientCredential(clientSecret), userTokenCache, null);
            string[] scopes = this.scopes.Split(new char[] { ' ' });

            AuthenticationResult result = await cca.AcquireTokenByAuthorizationCodeAsync(context.Code, scopes);
            var accessToken = result.AccessToken;
        }

        /// <summary>
        /// Handle failed authentication requests by redirecting the user to the home page with an error in the query string.
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
        {
            context.HandleResponse();
            context.Response.Redirect("/?errormessage=" + context.Exception.Message);
            return Task.FromResult(0);
        }
    }
}

Here is an sample for your reference.

Sign up to request clarification or add additional context in comments.

3 Comments

I have tried your solution but still not solved my problems. My Actual requirement is While loading a page it should it should check is this window is authenticated by Azure, If it is not then it should show login window, if it is already authenticated then need to get login ID and Token. Our project is Wep Page[ not MVC]. Can you please help me for creating a sample application for this.
After doing some changes it working in my project, but I am facing two issues 1. Latest NuGet pakages will not work, we need to keep old packages. 2. Azure Login is taking from this project memory, not taking from azure Applications page [Our project link load from Azure Applications, so azure login user should be come for this project]
@SijoyRajan You can refer to the answer here. stackoverflow.com/a/43537198/10504999
0

Your Page_Load uses incorrect logic. Move all the code you have under the comment (// below codes...) to an 'else' clause for your 'if !Request.IsAuthenticated'. The if statement will redirect the user to AAD for authentication. After authentication, when the method is executed again you will fall into the 'else' clause. Furthermore, by the time you are in the 'else' clause the id_token has been validated and converted into a ClaimsPrincipal. All the claims which came in the id_token were converted into individual items in its claims bag - just iterate over that bag to see what's there (better still use this sample). You can see in Fiddler what all is happening on the wire.

Since you are only doing authentication (scope = OpenIdProfile and responsetype=idToken) you will not get any refresh or access token. The latter is only needed if your app needs to call another API. Refreshing is done by AAD holding on to a session cookie. You should also create a user authn cookie, which is valid for same time as the id_token and redo the authentication when it expires. This sample is specific to WebForms.

4 Comments

I have tried your solution but still not solved my problems. My Actual requirement is I have a Web Application with form authentication. It will pass the user name and password to one service and validate it and send back a session ID. This Project I need to convert to AzureAD. So my expectation is
I have tried your solution but still not solved my problems. My Actual requirement is I have a Web Application with form authentication. It will pass the user name and password to one service and validate it and send back a session ID. This Project I need to convert to AzureAD. So Can you please help me for creating a simple application that should get UserID and token while loading default page.
Why did the sample not solve your problem? You should not take your existing pattern (get userid/pwd and exchange for token) and attempt to apply it to AAD (or any modern token issuer). You should convert it to a pattern in which your application delegates the job of getting and verifying user credentials and sending you a token. Familiarize yourself with the sample and explain why it does not work for you. (There is an [anti-] pattern which allows an application to collect userid/pwd and exchange for token - its called Resource Owner Password. You should NOT use it).
We have two Projects 1 is WebForm and 2 is Web Service. Our all DB communications are running in Web Service.we need to validate AzureAD in WebForm [It is working]. We need a token from webForm, that token will send to WebService then WebService will validate the token and return sessionID. Then all the forms will work in current workflow using sessionid. So can you please help me to get a Token from WebForms and it should able to validate in WebService. Note: User has azure Application page and it will contain this web page link. So this web page should take the user from azure aplication

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.