Coder Social home page Coder Social logo

azure-samples / active-directory-b2c-dotnet-webapp-and-webapi Goto Github PK

View Code? Open in Web Editor NEW
260.0 59.0 233.0 2.34 MB

A combined sample for a .NET web application that calls a .NET web API, both secured using Azure AD B2C

Home Page: http://aka.ms/aadb2c

License: MIT License

C# 8.45% CSS 0.34% HTML 3.51% JavaScript 87.66% ASP.NET 0.04%
microsoft identity azure-ad-b2c azure-active-directory dotnet webapp webapi asp-net

active-directory-b2c-dotnet-webapp-and-webapi's Introduction

page_type description languages products
sample
The sample covers calling an OpenID Connect identity provider (Azure AD B2C) and acquiring a token from Azure AD B2C using MSAL.
csharp
dotnet
azure
azure-active-directory

We have renamed the default branch to main. To rename your local repo follow the directions here.

Azure AD B2C: Call an ASP.NET Web API from an ASP.NET Web App

This sample contains a solution file that contains two projects: TaskWebApp and TaskService.

  • TaskWebApp is a "To-do" ASP.NET MVC web application where the users enters or updates their to-do items. These CRUD operations are performed by a backend web API. The web app displays the information returned from the ASP.NET Web API.
  • TaskService is the backend ASP.NET API that manages and stores each user's to-do list.

The sample covers the following:

  • Calling an OpenID Connect identity provider (Azure AD B2C)
  • Acquiring a token from Azure AD B2C using MSAL

How To Run This Sample using your own Azure AD B2C Tenant

After cloning this repo, configure the sample to use your own Azure AD B2C tenant. In this section, you'll learn how to configure the ASP.NET Web Application and the ASP.NET Web API to work with your own Azure AD B2C Tenant.

Step 1: Get your own Azure AD B2C tenant

First, you'll need an Azure AD B2C tenant. If you don't have an existing Azure AD B2C tenant that you can use for testing purposes, you can create your own by following these instructions.

Step 2: Create your own policies

This sample uses three types of policies: a unified sign-up/sign-in policy, a profile editing policy, and a password reset policy. Create one policy of each type by following the built-in policy instructions. You may choose to include as many or as few identity providers as you wish.

If you already have existing policies in your Azure AD B2C tenant, feel free to re-use those policies in this sample.

Make sure that all the three policies return User's Object ID and Display Name on Application Claims. To do that, on Azure Portal, go to your B2C Directory then click User flows (policies) on the left menu and select your policy. Then click on Application claims and make sure that User's Object ID and Display Name is checked.

Step 3: Register your ASP.NET Web API with Azure AD B2C

Follow the instructions at register a Web API with Azure AD B2C to register the ASP.NET Web API sample with your tenant. Registering your Web API allows you to define the scopes that your ASP.NET Web Application will request access tokens for.

Provide the following values for the ASP.NET Web API registration:

  • Provide a descriptive Name for the ASP.NET Web API, for example, My Test ASP.NET Web API. You will identify this application by its Name whenever working in the Azure portal.
  • Set the platform to Web and the Reply URI to https://localhost:44332/. This is the port number that this ASP.NET Web API sample is configured to run on.
  • Create the application.
  • Once the application is created, open your My Test ASP.NET Web API application and then open the Expose an API window (in the left nav menu).
  • Set the AppID URI to demoapi. This AppID URI is a unique identifier representing this particular ASP.NET Web API. The AppID URI is used to construct the scopes that are configured in your ASP.NET Web Application. For example, in this ASP.NET Web API sample, the scope will have the value https://<your-tenant-name>.onmicrosoft.com/demoapi/read
  • Add the following 2 scopes:
    • Scope named read followed by a display name and description of demoing a read scenario.
    • Scope named write followed by a display name and description of demoing a write scenario.

Step 4: Register your ASP.NET Web Application with Azure AD B2C

Follow the instructions at register a Web Application with Azure AD B2C

Your web application registration should include the following information:

  • Provide a descriptive Name for your web application, for example, My Test ASP.NET Web Application. You can identify this application by its Name within the Azure portal.
  • Set the platform to Web and the Reply URI to https://localhost:44316/ This is the port number that this ASP.NET Web Application sample is configured to run on.
  • Create your application.
  • Once the application is created, from the menu select Authentication. In the Implicit grant section, select Access tokens and click Save.
  • Next, create a Web App client secret. From the left menu select Certificates & secrets and click New client secret. Note: You will only see the secret once. Make sure you copy it.
  • From the menu choose API permissions. Click Add a permission, switch to the My APIs tab, and select the name of the Web API you registered previously, for example My Test ASP.NET Web API. Select the scope(s) you defined previously, for example, read and write and select Add permissions.

Step 5: Configure your Visual Studio project with your Azure AD B2C app registrations

In this section, you will change the code in both projects to use your tenant.

⚠️ Since both projects have a Web.config file, pay close attention which Web.config file you are modifying.

Step 5a: Modify the TaskWebApp project

  1. Open the Web.config file for the TaskWebApp project.

  2. Find the key ida:Tenant and replace the value with your <your-tenant-name>.onmicrosoft.com.

  3. Find the key ida:AadInstance and replace the value with your <your-tenant-name>.b2clogin.com.

  4. Find the key ida:TenantId and replace the value with your Directory ID. You can get it by navigating to the registration information of one of your apps and copying the value of the Directory (tenant) ID property.

  5. Find the key ida:ClientId and replace the value with the Application ID from your web application My Test ASP.NET Web Application registration in the Azure portal.

  6. Find the key ida:ClientSecret and replace the value with the Client secret from your web application in the Azure portal.

  7. Find the keys representing the policies, e.g. ida:SignUpSignInPolicyId and replace the values with the corresponding policy names you created, e.g. b2c_1_SiUpIn

  8. Change the api:ApiIdentifier key value to the App ID URI of the API you specified in the Web API registration. This App ID URI tells B2C which API your Web Application wants permissions to.

    <add key="api:ApiIdentifier" value="https://<your-tenant-name>.onmicrosoft.com/demoapi/" />

    📝 Make sure to include the trailing '/' at the end of your ApiIdentifier value.

  9. Find the keys representing the scopes, e.g. api:ReadScope and replace the values with the corresponding scope names you created, e.g. read

Step 5b: Modify the TaskService project

  1. Open the Web.config file for the TaskService project.
  2. Find the key ida:Tenant and replace the value with your <your-tenant-name>.onmicrosoft.com.
  3. Find the key ida:AadInstance and replace the value with your <your-tenant-name>.b2clogin.com.
  4. Find the key ida:ClientId and replace the value with the Application ID from your web API My Test ASP.NET Web API registration in the Azure portal.
  5. Find the key ida:SignUpSignInPolicyId and replace the value with the policy name you created, e.g. b2c_1_SiUpIn
  6. Find the keys representing the scopes, e.g. api:ReadScope and api:WriteScope and replace the values with the corresponding scope names you created if needed, e.g. read and write

Step 5c: Run both projects

You need to run both projects at the same time. If you did not complete the demo tenant instructions above, you need to configure Visual Studio for multiple startup projects.

You can now perform all the previous steps as seen in the demo tenant environment.

Known Issues

  • MSAL cache needs a TenantId along with the user's ObjectId to function. It retrieves these two from the claims returned in the id_token. As TenantId is not guaranteed to be present in id_tokens issued by B2C unless you perform the steps listed in this document, if you are following the workarounds listed in the doc and tenantId claim (tid) is available in the user's token, then please change the code in ClaimsPrincipalsExtension.cs GetB2CMsalAccountId() to let MSAL pick this from the claims instead.

  • This sample code by default only supports verifying the token signatures of multiple policies (signup, profile edit, password reset etc), if all those policies are configured to use the same token signing key. Otherwise, if one policy is using a different token signing key you will get the error:

    IDX10501: Signature validation failed. Unable to match keys

    For instance, this means that you can't use a custom policy for SignUpSignIn, and then a built in user flow policy for profile edit. As custom policies and user flows will always have different token signing keys. This is because for AAD B2C each user flow routes to a separate authorization server.

Next Steps

Customize your user experience further by supporting more identity providers. Checkout the docs belows to learn how to add additional providers:

Microsoft

Facebook

Google

Amazon

LinkedIn

Additional information

Additional information regarding this sample can be found in our documentation:

Questions & Issues

Please file any questions or problems with the sample as a github issue. You can also post on StackOverflow with the tag azure-ad-b2c.

active-directory-b2c-dotnet-webapp-and-webapi's People

Contributors

aremo-ms avatar aruanoguate avatar bgavrilms avatar danieldobalian avatar dependabot[bot] avatar gladjohn avatar gladwinjohnson avatar gsacavdm avatar jennyf19 avatar jmprieur avatar microsoftopensource avatar mmacy avatar msftgits avatar neha-bhargava avatar parakhj avatar pmaytak avatar rari2012 avatar sameerk-msft avatar saraford avatar spottedmahn avatar supernova-eng avatar trwalke avatar valnav avatar waldekmastykarz avatar weznagwama avatar whyleee avatar yeya avatar yoelhor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

active-directory-b2c-dotnet-webapp-and-webapi's Issues

How can we get email on successful authentication using OpenIdConnect?

I'm using following options for OpenIdConnectAuthenticationOptions object but not getting Email or profile data in success response.

TokenValidationParameters = new TokenValidationParameters {
NameClaimType = "email",
SaveSigninToken = true //important to save the token in boostrapcontext
},
// Specify the scope by appending all of the scopes requested into one string (seperated by a blank space)
Scope = $"openid profile email offline_access {ReadTasksScope} {WriteTasksScope}",
ResponseType = "id_token",

Thanks!

Sample is broken when upgrading MSAL to v1.1.0 Preview

Since MSAL v1.1.0Preview is now available, I tried updating the sample to use it. The same code that is working with the previous alpha version now fails with:

AADSTS70011: The provided value for the input parameter 'scope' is not valid. The scope https://mytenant.onmicrosoft.com/tasks/read https://mytenant.onmicrosoft.com/tasks/write offline_access openid profile is not valid.

The scopes offline_access , openid and profile are added somewhere by MSAL, why?

StackTrace is here:
stackTrace.txt

Azure B2C built in policies - Bad request

Hi Team,

Currently we are using Azure B2C built in policies for signin, signup and logout. Sometimes, while navigating to these pages, we are getting "Bad request" and application getting down. Can you please guide me on how to handle this situation.
Below is the URL we captured in browser network.

https://login.microsoftonline.com/xxxx.xxxx.com/B2C_1_DEV_SignIn/api/CombinedSigninAndSignup/confirmed?csrf_token=bGVPaG5JbzFwU1BIV1o3MHBtZ24xU2VBdlFoYWsyNkVDbHdTOXVGUVhicHJUQVpnQTBsWEJzN2pyQ1MwaThsTDljQjY5VUVUMmh4R2crcmNtMDVEeFE9PTsyMDE4LTExLTA4VDE4OjA3OjE0LjgzNjQ3NDdaO05aOFg4THBlc3lnejZoNnVZME85aWc9PTt7Ik9yY2hlc3RyYXRpb25TdGVwIjoxfQ==&tx=StateProperties=eyJUSUQiOiJiOThhNTI3MS1iZTE3LTRiMmMtOWE0My04ZTdkMjAzZDhiYzMifQ&p=B2C_1_DEV_SignIn&diags=%7B%22pageViewId%22%3A%22d79b1c9c-f67f-46fb-8e0b-0703f626ff99%22%2C%22pageId%22%3A%22CombinedSigninAndSignup%22%2C%22trace%22%3A%5B%7B%22ac%22%3A%22T005%22%2C%22acST%22%3A1541700435%2C%22acD%22%3A3%7D%2C%7B%22ac%22%3A%22T021%20-%20URL%3Ahttps%3A%2F%2Fsidentity.blob.core.windows.net%2Fb2c-container-dev%2FTT.CustomPages%2Funified.html%22%2C%22acST%22%3A1541700435%2C%22acD%22%3A16%7D%2C%7B%22ac%22%3A%22T029%22%2C%22acST%22%3A1541700435%2C%22acD%22%3A29%7D%2C%7B%22ac%22%3A%22T004%22%2C%22acST%22%3A1541700435%2C%22acD%22%3A24%7D%2C%7B%22ac%22%3A%22T019%22%2C%22acST%22%3A1541700435%2C%22acD%22%3A66%7D%2C%7B%22ac%22%3A%22T003%22%2C%22acST%22%3A1541700435%2C%22acD%22%3A79%7D%2C%7B%22ac%22%3A%22T030Online%22%2C%22acST%22%3A0%2C%22acD%22%3A0%7D%2C%7B%22ac%22%3A%22T018%22%2C%22acST%22%3A1541700606%2C%22acD%22%3A4758%7D%2C%7B%22ac%22%3A%22T002%22%2C%22acST%22%3A0%2C%22acD%22%3A0%7D%5D%7D

Hosting in IIS 7

Hello all,
I am using visual studio 2015 and IIS Express for the development and everything works as expected. But when I switch the server to Local IIS (under the properties of TaskWebApp) it starts throwing the following exception -
image

InvalidOperationException: IDX10803: Unable to create to obtain configuration from: 'https://login.microsoftonline.com/tfp/XXXXB2CTenant.onmicrosoft.com/B2C_1_B2C_SignIn/v2.0/.well-known/openid-configuration'.]

What could be the possible reason to this and how to solve it.

Thanks
Prabhanjan

B2C adding &diags= <long text> to URLs "Bad Request - Request Too Long"

Hi,

Anyone know why and how to turn off B2C adding

&diags={"pageViewId":"dd1046f8-44b7-46cf-9357-7213956dc62e","pageId":"ClaimsProviderSelection","trace":[{"ac":"T005","acST":1520424416,"acD":1},{"ac":"T021 - URL:https://xxxxx/idpSelector.html","acST":1520424416,"acD":49},{"ac":"T029","acST":1520424416,"acD":42},{"ac":"T004","acST":1520424416,"acD":2},{"ac":"T019","acST":1520424416,"acD":65},{"ac":"T003","acST":1520424416,"acD":4},{"ac":"T002","acST":0,"acD":0}]}

to login URLs

causing

Bad Request - Request Too Long
HTTP Error 400. The size of the request headers is too long.

WebApi Updated to latest Microsoft.Owin.Security.* packages and cannot find IIssuerSecurityTokenProvider inteface

Hi, I was running properly on protecting the WebApi with AD B2C AuthBearer token, after I upgraded to latest packages of Microsoft.Owin.Security.* I cannot find the definition for IIssuerSecurityTokenProvider anymore but when I try to use IIssuerSecurityKeyProvider instead of IIssuerSecurityTokenProvider I am running into a whole host of other issues.
Can somebody point me in the correct direction? specifically how Do I get the Owin setup part with code samples using the latest packages.

MSALPerUserSessionTokenCache not correctly persisting tokencache

The logic for UserTokenCacheBeforeAccessNotification and UserTokenCacheAfterAccessNotification has been swapped. the code should load the cache before access and persist after access. Simply swapping the code inside the methods fixed this problem for me.

Error reading to do list: Null user was passed in AcquiretokenSilent API. Pass in a user object or call acquireToken authenticate.

I've gotten my the web app and my ad tenant working so that I'm able to sign-in/create users.

I've verified this by reviewing my claims:

image

Now I'm trying to get the api going. When I visit the tasks view I get:

Error reading to do list: Null user was passed in AcquiretokenSilent API. Pass in a user object or call acquireToken authenticate.

I see that user is null and it shouldn't be based upon the error message I received. What am I doing wrong?

image

ConfidentialClientApplication.Users is obsolete

Latest version with libraries updated as of 1/27/2019 this demo no longer works.

ClientApplicationBase.Users is obsolete - Use GetAccountesAsync instead

ConfidentialClientApplication cca = new ConfidentialClientApplication(Startup.ClientId, Startup.Authority, Startup.RedirectUri, new ClientCredential(Startup.ClientSecret), userTokenCache, null);

InvalidOperationException: IDX20803: in TaskService

OpenIdConnectConfiguration config = Task.Run(_configManager.GetConfigurationAsync).Result in RetrieveMetadata() method of TaskService project fails !
The error is:
[InvalidOperationException: IDX20803: Unable to obtain configuration from: '[PII is hidden by default. Set the 'ShowPII' flag in IdentityModelEventSource.cs to true to reveal it.]'.]

I tried with your demo enviroment and with my own Azure AD B2C Tenant
and the error is the same

What am I doing wrong ?

[Bug] an extra `/` is added to the URL

Customers have reported here and in SO that an extra / is added to the B2C Url.
They get a 404 with the Azure B2C URL being messed up, i.e.

https://[company].b2clogin.com/[company].onmicrosoft.com//v2.0/.well-known/openid-configuration/v2.0/.well-known/openid-configuration'.]

The URL was fine in both _metadataEndpoint and MetadataAddress in the Startup-cs class
Corresponding comment

cc: @jmprieur - in case you've heard anything about this as well.

Error: Sending the request from Localhost don't work

Hi,
i'm working on Win10 with VS 2015 running your sample.
Many thanks for this excellent way of showing how Azure B2C is working to secure an API.

I'm running the example local. I managed to get logging in to the website. But the request will not send because of SSL issues in localhost.

Has anyone a suggest how to fix that?

Many thanks in advance,
regards,
Ralf

Issues after authentication page

I experience all sorts of issues after I have logged in with e-mail address and pw. The page sometimes doesn't come back, it's bouncing between microsoft authentication website and the application. Sometimes it comes back with message "Error. We're having trouble logging you in" with no more explanation. this time I get the same with following explanation: "IDX21323: RequireNonce is '[PII is hidden by default. Set the 'ShowPII' flag in IdentityModelEventSource.cs to true to reveal it.]'. OpenIdConnectProtocolValidationContext.Nonce was null, OpenIdConnectProtocol.ValidatedIdToken.Payload.Nonce was not null. The nonce cannot be validated. If you don't need to check the nonce, set OpenIdConnectProtocolValidator.RequireNonce to 'false'. Note if a 'nonce' is found it will be evaluated.". On the other hand, I see my user name in the above right-hand menu and "Sign out" next to it, indicating I'm logged in.

Works for Demo Env, but not for my B2C

I'm able to run the demo environment as expected.

Running against my own B2C tenant, I'm unable to get an AccessToken from AcquireTokenByAuthorizationCodeAsync. AccessToken is always null.

The glaring difference I can see is that one of my resulting claims are different.

  1. The demo environment has the default policy under a claim type "http://schemas.microsoft.com/claims/authnclassreference", while my B2C resulting claim has the default police under a claim type of "tfp"

I've double checked all my web.config, setup, and scopes.
I've deleted and re-added the application on the B2C side and created a fresh user.
Always clearing cookie, same in Chrome and Edge.

No luck. Any help appreciated.

HELP : Session and Token Expiry issues

I created b2c-dotnet-webapp-and-webapi type application. But After 20 min or after sometime(nearly 30 min not sure) My WebApp is throwing exception during the Ajax call saying 401(Unauthorized). This exception is coming when ajax call hitting the WebApp controller So this error is coming from OWIN middleware not sure why.

My Startup.cs settings are

`
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(_aadB2CPasswordResetPolicy));
app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(_aadB2CSignInPolicy));
}

    private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
    {
        context.HandleResponse();
        if (context.Exception is OpenIdConnectProtocolInvalidNonceException &&
            context.Exception.Message.Contains("IDX10316"))
        {
            // Redirect to the originally requested URL
            context.Response.Redirect(context.Request.Uri.PathAndQuery);
        }
        else
        {
            var trackingId = Guid.NewGuid().ToString("N");
            _telemetry.TrackException(
                context.Exception,
                new Dictionary<string, string> {{"SignInErrorTrackingId", trackingId}});
            context.Response.Redirect($"/Home/SignInError?trackingId={trackingId}");
        }
        return Task.FromResult(0);
    }

    private OpenIdConnectAuthenticationOptions CreateOptionsFromPolicy(string policy)
    {
        return new OpenIdConnectAuthenticationOptions
        {
            // For each policy, give OWIN the policy-specific metadata address, and
            // set the authentication type to the id of the policy
            MetadataAddress = string.Format(_aadInstance, _tenant, policy),
            AuthenticationType = policy,

            // These are standard OpenID Connect parameters, with values pulled from web.config
            ClientId = _clientId,
            RedirectUri = _redirectUri,
            PostLogoutRedirectUri = _redirectUri,
            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                AuthenticationFailed = OnAuthenticationFailed,
            },
            Scope = "openid",
            ResponseType = "id_token",

            TokenValidationParameters = new TokenValidationParameters
            {
                NameClaimType = "name",
                SaveSigninToken = true,
            },
        };
    }
}` 

If I am modifying the code

app.UseCookieAuthentication(new CookieAuthenticationOptions { SlidingExpiration = true, ExpireTimeSpan = TimeSpan.FromMinutes(60) });,
And adding the below setting in OpenIdConnectAuthenticationOptions
UseTokenLifetime = false,

Then My WebApp is working for 1 hour and after that again I am facing the 401 Unauthorized. This time my WEAPI giving this error because by default token is valid for 1 hour I guess.

Question : How can I manage the token issues if the token is expired after 1 hour during ajax call ? and What is best setting that I should have So that my middleware will not give me 401 after 20 min or some random time ?

Kindly Ignore if something I am doing terribly wrong. I am very new to this and don't have much idea.

Bad Request - Request Too Long

Upon signing into my tenant I'm receiving:

Bad Request - Request Too Long
HTTP Error 400. The size of the request headers is too long.

Attached is the full request: Bad Request - Request Too Long.txt

The first few sign-ins worked. I'm not sure what exactly changed to make it stop working. Any thoughts?

The request was aborted: Could not create SSL/TLS secure channel when logged in user visiting webapi from webapp

Great repo.

I have problem below when I click To-Do List button on WebApp, even Claims page is working and user has logged in.

The request was aborted: Could not create SSL/TLS secure channel.

It throws exception above on this line client.SendAsync below:


 [Authorize]
    public class TasksController : Controller
    {
        private String apiEndpoint = Startup.ServiceUrl + "/api/tasks/";

        // GET: Makes a call to the API and retrieves the list of tasks
        public async Task<ActionResult> Index()
        {
            try
            {
                // Retrieve the token with the specified scopes
                var scope = new string[] { Startup.ReadTasksScope };
                string signedInUserID = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
                TokenCache userTokenCache = new MSALSessionCache(signedInUserID, this.HttpContext).GetMsalCacheInstance();
                ConfidentialClientApplication cca = new ConfidentialClientApplication(Startup.ClientId, Startup.Authority, Startup.RedirectUri, new ClientCredential(Startup.ClientSecret), userTokenCache, null);

                var user = cca.Users.FirstOrDefault();
                if (user == null)
                {
                    throw new Exception("The User is NULL.  Please clear your cookies and try again.  Specifically delete cookies for 'login.microsoftonline.com'.  See this GitHub issue for more details: https://github.com/Azure-Samples/active-directory-b2c-dotnet-webapp-and-webapi/issues/9");
                }

                AuthenticationResult result = await cca.AcquireTokenSilentAsync(scope, user, Startup.Authority, false);

                HttpClient client = new HttpClient();
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, apiEndpoint);

                // Add token to the Authorization header and make the request
                request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
                HttpResponseMessage response = await client.SendAsync(request);  //throw exception here

                // Handle the response
                switch (response.StatusCode)
                {
//     ...
                }
            }
            catch (Exception ex)
            {
                return ErrorAction("Error reading to do list: " + ex.Message);
            }
        }

any idea?

Update
I am able to use it in demo environment, but failed when setting up in Azure AD B2C Tenant running the apps localy.

The url is https://localhost:44332//api/tasks/

Logged In user identifier

Hi,

How can I recuperate the GUID of the logged in user in a controller of the app ? What's the code?

Thanks
Rgds

Question: On Successful SignUp / Register event?

Is it possible to subscribe to an event when a user has successfully signed up/registered?

`

        options.Events = new OpenIdConnectEvents()
        {   
            OnRedirectToIdentityProvider = OnRedirectToIdentityProvider,
            OnRemoteFailure = OnRemoteFailure,
            OnAuthorizationCodeReceived = OnAuthorizationCodeReceived,
            OnAuthenticationFailed = OnAuthenticationFailed,
            OnMessageReceived = OnMessageReceived,
            OnRedirectToIdentityProviderForSignOut = OnRedirectToIdentityProviderForSignOut,
            OnRemoteSignOut = OnRemoteSignOut,
            OnSignedOutCallbackRedirect = OnSignedOutCallbackRedirect,
            OnTicketReceived = OnTicketReceived,
            OnTokenResponseReceived = OnTokenResponseReceived,
            OnTokenValidated = OnTokenValidated,
            OnUserInformationReceived = OnUserInformationReceived
            //OnSignUp/OnRegistered? or maybe a property from one of the events above which uniquely identifies a signup procedure?
        };

`

Basically our goal is to run some extra code when a user has signed up... ex validation etc...

Can/should OpenIdConnectCachingSecurityTokenProvider be fault tolerant

Copied from AzureADQuickStarts/B2C-WebApp-WebAPI-OpenIDConnect-DotNet#9 (comment) as @parakhj says the old sample will be deprecated...

Issue I had today was my API couldn't connect to Azure B2C, during startup which caused a yellow screen with the API.

[WebException: The remote server returned an error: (500) Internal Server Error.]
   System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult) +606
   System.Net.WebClient.GetWebResponse(WebRequest request, IAsyncResult result) +19
   System.Net.WebClient.DownloadBitsResponseCallback(IAsyncResult result) +91
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +92
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
   Microsoft.IdentityModel.Protocols.<GetDocumentAsync>d__4.MoveNext() in c:\workspace\WilsonForDotNet45Release\src\Microsoft.IdentityModel.Protocol.Extensions\Configuration\GenericDocumentRetriever.cs:42

[IOException: Unable to get document from: https://login.microsoftonline.com/contoso.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=B2C_1_StandardSignup]
   Microsoft.IdentityModel.Protocols.<GetDocumentAsync>d__4.MoveNext() in c:\workspace\WilsonForDotNet45Release\src\Microsoft.IdentityModel.Protocol.Extensions\Configuration\GenericDocumentRetriever.cs:48
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +92
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
   Microsoft.IdentityModel.Protocols.<GetAsync>d__0.MoveNext() in c:\workspace\WilsonForDotNet45Release\src\Microsoft.IdentityModel.Protocol.Extensions\Configuration\OpenIdConnectConfigurationRetriever.cs:81
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +92
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
   System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task) +25
   Microsoft.IdentityModel.Protocols.<GetConfigurationAsync>d__3.MoveNext() in c:\workspace\WilsonForDotNet45Release\src\Microsoft.IdentityModel.Protocol.Extensions\Configuration\ConfigurationManager.cs:198

Given that we are making an RPC call which can fail, does it make sense for the policy acquisition not to fail/throw so that the API doesn't crash at startup, it just can't authenticate using OAuth. When the service comes back, it will then pick up the policies, something like...

private void RetrieveMetadata()
{
	_synclock.EnterWriteLock();
	try
	{
		OpenIdConnectConfiguration config = Task.Run(_configManager.GetConfigurationAsync).Result;
		_issuer = config.Issuer;
		_tokens = config.SigningTokens;
	}
	catch (AggregateException ex)
	{
		// Unwrap and log
	}
	catch (Exception ex)
	{
		// Log failure
	}
	finally
	{
		_synclock.ExitWriteLock();
	}
}

What I then get if the front-end can talk to B2C are
DX10500: Signature validation failed. Unable to resolve SecurityKeyIdentifier: 'SecurityKeyIdentifier errors as the issuer/token are null in the API.

What I don't know is if this is appropriate, i.e. JwtFormat keep calling the IIssuerSecurityTokenProvider, or am I abusing the interface.

AcquireTokenByAuthorizationCodeAsync throw “client info is null” error

I'm using AAD B2C custom policy based on 'SocialAndLocalAccounts', setting the AAD applications and encryption keys as mention here. While running the application it seems B2C returns valid ID token and authorization code, but when MSAL (1.1.0-preview) executes AcquireTokenByAuthorizationCodeAsync I got following error message, looks like MSAL doesn't able to save the tokens (access and refresh) to local cache.
Message = "client info is null"
ErrorCode = "json_parse_failed"

Note: the same policy, with same AAD application still working in the previous version of this demo app. The previous version of this application used MSAL version 1.0.304142221-alpha

StackTrace = " at Microsoft.Identity.Client.Internal.ClientInfo.CreateFromJson(String clientInfo)
at Microsoft.Identity.Client.Internal.Requests.RequestBase.SaveTokenResponseToCache()
at Microsoft.Identity.Client.Internal.Requests.RequestBase.PostTokenRequest()
at Microsoft.Identity.Client.Internal.Requests.RequestBase.d__33.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Identity.Client.ConfidentialClientApplication.d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Identity.Client.ConfidentialClientApplication.d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at TaskWebApp.Startup.d__20.MoveNext() in C:\MyProjects\Microsoft.SDP.Identity\Microsoft.SDP.Identity.DemoWebApp\App_Start\Startup.Auth.cs:line 148

Thank you very much for your assistance in this matter.
Yoel

Error. We're having trouble signing you in. Please sign in again. Unauthorized

When I try to Access the To-do list I get the following message.

It finds my claim just fine, and it says I'm signed in.

Web.config:

<add key="ida:Tenant" value="b2cmax.onmicrosoft.com" />
<add key="ida:ClientId" value="2f4c85d0-6471-4080-a73c-b7e7811f273b" />
<add key="ida:ClientSecret" value="--removed--" />
<add key="ida:AadInstance" value="https://login.microsoftonline.com/tfp/{0}/{1}/v2.0/.well-known/openid-configuration" />
<add key="ida:RedirectUri" value="https://localhost:44316/" />

<add key="ida:SignUpSignInPolicyId" value="b2c_1_susi" />
<add key="ida:EditProfilePolicyId" value="b2c_1_profile_edit" />
<add key="ida:ResetPasswordPolicyId" value="b2c_1_p_reset" />

<!-- Uncomment the localhost url if you want to run the API locally -->
<!--<add key="api:TaskServiceUrl" value="https://aadb2cplayground.azurewebsites.net/" /> -->
<add key="api:TaskServiceUrl" value="https://localhost:44332/" />

<!-- The following settings is used for requesting access tokens -->
<add key="api:ApiIdentifier" value="https://b2cmax.onmicrosoft.com/tasks/" />
<add key="api:ReadScope" value="read" />
<add key="api:WriteScope" value="write" />`

Do I need to make any changes to TaskService Web Config?

AuthenticationResult.AccessToken is null in OnAuthorizationCodeReceived

Great demo so far.

I`ve configured the app like the walkthrough mentioned but when the OnAuthorizationCodeReceived is called no AccessToken will be received (empty).

The Policies are working fine. I can login and change some settings. However accessing the Tasks Service does not work and returns an "Unauthorized" on the screen when clicking on ToDo-List.

  1. When i try to dig into the documentation at githhub i found inconsitencies. The class NaiveSessionCache is not available and the acquireToken-Function of Controllers\TasksController.cs is inlined.

  2. Should the "App-ID-URI" end with "Tasks" or "api"? The documentation is somehow misleading. ;-(

Any help would be appreciated!

404(Not Found) Error while trying to Sign up/Sign in

Getting 404(Not Found) Error while trying to sign up/sign in for the 'TaskWebApp'(after configuring the corresponding policy). I have ran the user flow(policy) from the portal and it seems to working fine. Also, I had updated the 'ida:Tenant', 'ida:TenantId', 'ida:ClientId', 'ida:ClientSecret', 'ida:RedirectUri' & 'ida:SignUpSignInPolicyId' keys in the 'appsettings' section of the Web.config with the proper values before running the application. Screenshots are attached below for reference:

image

image

I'm giving the whole stack trace below. Am I missing anything? Any assistance would be greatly helpful. Thanks in advance!

`
[HttpRequestException: Response status code does not indicate success: 404 (Not Found).]
System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode() +92844
Microsoft.IdentityModel.Protocols.d__8.MoveNext() +375

[IOException: IDX20804: Unable to retrieve document from: '[PII is hidden]'.]
Microsoft.IdentityModel.Protocols.d__8.MoveNext() +662
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.IdentityModel.Protocols.OpenIdConnect.d__3.MoveNext() +291
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task) +25
Microsoft.IdentityModel.Protocols.d__24.MoveNext() +1129

[InvalidOperationException: IDX20803: Unable to obtain configuration from: '[PII is hidden]'.]
Microsoft.IdentityModel.Protocols.d__24.MoveNext() +1586
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.Owin.Security.OpenIdConnect.d__8.MoveNext() +432
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.Owin.Security.Infrastructure.d__40.MoveNext() +272
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.Owin.Security.Infrastructure.d__39.MoveNext() +271
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.Owin.Security.Infrastructure.d__34.MoveNext() +158
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.Owin.Security.Infrastructure.d__5.MoveNext() +659
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.d__7.MoveNext() +179
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.Owin.Security.Infrastructure.d__5.MoveNext() +519
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.d__7.MoveNext() +179
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.d__12.MoveNext() +180
Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.StageAsyncResult.End(IAsyncResult ar) +69
Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContext.EndFinalWork(IAsyncResult ar) +64
System.Web.AsyncEventExecutionStep.InvokeEndHandler(IAsyncResult ar) +156
System.Web.AsyncEventExecutionStep.OnAsyncEventCompletion(IAsyncResult ar) +9900408`

Asp.NET Core

This repo is linked directly from documentation specific to ASP.NET Core.

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/azure-ad-b2c-webapi?view=aspnetcore-2.1

See link Call a .NET web API from a .NET web app using Azure AD B2C. below the code sample within Next Steps section)

Yet the codebase here is targeting the full NET Framework and legacy MVC. I've yet to find an adequate sample that performs the same functionality as this application but targeting Core.

Can we get a branch or repo with a more up to date target?

Unable to authenticate to API & access to-do list function of application

I am having issues starting the sample application and accessing the To Do List section of the app.

The error I receive is -
We're having trouble signing you in.
Error. Status code = InternalServerError

I am able to login to the application successfully, but not able to access the to do list function.
I think the issue stems from the PublishedScopes. In the documentation, it does not tell which scopes should be created in the API to the web app, and there are no default values. I created values 'read','write','user_impersonation' and granted the web app access but this did not resolve my issue.

TaskService web.config

<appSettings>
    <add key="webpages:Version" value="3.0.0.0" />
    <add key="webpages:Enabled" value="false" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
    <add key="ida:AadInstance" value="https://login.microsoftonline.com/{0}/v2.0/.well-known/openid-configuration?p={1}" />
    <add key="ida:Tenant" value="montelb2c.onmicrosoft.com" />
    <add key="ida:ClientId" value="0340d8fc-1c37-4bc5-818c-28acfef6feee" />
    <add key="ida:SignUpSignInPolicyId" value="B2C_1A_signup_signinwithAAD" />

    <!-- The following settings is used for requesting access tokens -->
    <add key="api:ReadScope" value="read" />
    <add key="api:WriteScope" value="write" />
  </appSettings>

TaskWebApp web.config.

<appSettings>
 <add key="webpages:Version" value="3.0.0.0" />
 <add key="webpages:Enabled" value="false" />
 <add key="ClientValidationEnabled" value="true" />
 <add key="UnobtrusiveJavaScriptEnabled" value="true" />
 <add key="ida:Tenant" value="montelb2c.onmicrosoft.com" />
 <add key="ida:ClientId" value="b4b2384b-457d-4fa6-a9ff-953f1834be8e" />
 <add key="ida:ClientSecret" value="hidden" />
 <add key="ida:AadInstance" value="https://login.microsoftonline.com/tfp/{0}/{1}/v2.0/.well-known/openid-configuration" />
 <add key="ida:RedirectUri" value="https://localhost:44316/" />
 
 <add key="ida:SignUpSignInPolicyId" value="B2C_1A_signup_signinwithAAD" />
 <add key="ida:EditProfilePolicyId" value="B2C_1A_ProfileEdit" />
 <add key="ida:ResetPasswordPolicyId" value="B2C_1A_PasswordReset" />
 
 <!-- Uncomment the localhost url if you want to run the API locally -->
 <!--add key="api:TaskServiceUrl" value="https://aadb2cplayground.azurewebsites.net/" /-->
 <add key="api:TaskServiceUrl" value="https://localhost:44332/" />

 <!-- The following settings is used for requesting access tokens -->
 <add key="api:ApiIdentifier" value="https://montelb2c.onmicrosoft.com/tasks" />
 <add key="api:ReadScope" value="read" />
 <add key="api:WriteScope" value="write" />
 
</appSettings>

Please assist!

httpContext.Session is null in MSALSessionCache.Load

I have successfully setup the sample with my own Tenant. It is working well. When I create my own project from scratch and replicate every single thing down to the exact same dll's, it fails to reproduce the same results as the sample did. It fails when trying to Deserialize the HttpContext.Session within the MSALSessoCache Class, Load method. If I comment out the deserialize I can see that I am getting the token back with the proper information and claims. The deserialization results in a null object exception when casting to blob. Because I can see the user info and the fact that it works in the sample, I am assuming the Azure Tenant is correct.

I created the new MVC application with "No Authentication" , changed to HTTPS as well as updated the Project Url in properties. Copied the code over verifying the OWIN Startup.cs class and Startup.Auth.cs. Everything is identical with exception to the https redirect url and https TaskServiceUrl within the web.config. I have also verified that the proper https url has been added in the tenants application. setup with Azure B2C. Am I missing something?

Issue with Redirect Url in host Azure AD Application

The reply URL for making your own application didn't work for me. I had to consult this page. If you look to the closed issues there is an entry for the redirect URL not working. Once I

https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-add-identity-providers#feedback

"None of the redirect URLs work
None of these worked as a redirect URL:

https://your-B2C-tenant-name.b2clogin.com/your-B2C-tenant-name.onmicrosoft.com/oauth2/authresp
https://{your-tenant-name}.b2clogin.com/{your-tenant-id}/oauth2/authresp
https://{your-tenant-name}.b2clogin.com/{your-tenant-name}.onmicrosoft.com/oauth2/authresp
But using Fiddler, I figured out this worked:

https://login.microsoftonline.com/te/{your-tenant-name}.onmicrosoft.com/oauth2/authresp"

I don't know if you have to update the sample. The issue is closed by the admin but I still ran into this.

Thanks!

Owin Environment missing SessionId

I have downloaded the sample, built it and it worked. I substituted my tenant details and I was still able to login.

I then copied the various pieces of code over into my current project. Login fails with a null object reference at MSALSessionCache.ReadUserStateValue - httpContext.Session is null.

This is passed in at line 144 of StartupAuth.cs and is derived from notification.OwinContext.Environment["System.Web.HttpContextBase"] as HttpContextBase.

notification.OwinContext.Environment["System.Web.HttpContextBase"].Session is null

I ran the debug on the sample code and at that same point notification.OwinContext.Environment["System.Web.HttpContextBase"].Session = System.Web.HttpSessionStateWrapper and when I examined its properties saw that it contained a SessionId.

The sample is an MVC project whereas mine is a WebForms project I have only had to make one change

in the MVC project SignUpSignIn the code is:
if (!Request.IsAuthenticated)
{
HttpContext.GetOwinContext().Authentication.Challenge();
return;
}
whereas in the WebForms project the SignUpSignIn code is:
if (!Request.IsAuthenticated)
{
HttpContextBase context = new HttpContextWrapper(HttpContext.Current);
context.GetOwinContext().Authentication.Challenge();
return;
}
as in the WebForms project HttpContext.Current returns an HttpContext object rather than an HttpContextBase object.

I have gone round and round in circles trying to determine why the code in my WebForms project produces this null reference. Can anyone point me in the right direction?

This B2C quick-start/tutorial implementation is not correct aligned with Set redirect URLs to b2clogin.com for Azure Active Directory B2C

Hi, the b2c quick-start/tutorial implementation see "https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-quickstarts-web-app" respective download here "https://github.com/Azure-Samples/active-directory-b2c-dotnet-webapp-and-webapi/archive/master.zip" is not correct aligned and still using "login.microsoftonline.com" see https://docs.microsoft.com/en-us/azure/active-directory-b2c/b2clogin
See: active-directory-b2c-dotnet-webapp-and-webapi-master\TaskService\Web.config

See: active-directory-b2c-dotnet-webapp-and-webapi-master\TaskWebApp\Web.config

I hope this should soon get fixed?
Thank you

Verbosity for ID claims match not sufficient

Not really an issue (first github contribution sorry), but when attempting to match objectidentifier claim in the api\TasksController.cs, to a JWT where the claim doesn't exist, bombs out with a non-descriptive error.

We can add better error handling/checking here so it's more clear for people new to oath, like me :)

Note: I'm forking and creating a PR around this.

TaskService.TasksController ln36 db is empty

db is initialized on ln17 to a new list<Models.Task>, but I don't see anywhere db is getting loaded with tasks.

I do have Azure AD Web API setup with scopes for read and write.
I updated the web.config.

When i click on "To-Do List" on the web app, when I debug on the task service on TasksController ln 36, db is an empty list. I would think this would contain all scope options.

Not sure what I'm missing. Any ideas?

facing issue while uisng authorization_code

{"error":"invalid_grant","error_description":"AADB2C90085: The service has encountered an internal error. Please reauthenticate and try again.\r\nCorrelation ID: 4810f417-400c-4410-a312-00f528dd4490\r\nTimestamp: 2017-06-26 13:53:28Z\r\n"}

Using something else beside IIS Express, trying to use Azure

I have been messing around with some internal changes to the sample code, with no success outside of the IIS Express setup. My hope is that one could place TaskService and TaskWebApp into an Azure Web App service (or localhost) and update the code to point to your own AD B2C instance.

But, I have had no success in using either a localhost setup, or a setup on azurewebsites.net. I did change the published scopes to fir the values, below but no success. Any help in understanding how to set this up from a azurewebsites.net standpoint would be appreciated.

<add key="ida:SignUpSignInPolicyId" value="b2c_1_SecondPolicy" />
<add key="ida:EditProfilePolicyId" value="b2c_1_ProfileEditing1" />
<add key="ida:ResetPasswordPolicyId" value="b2c_1_ResetPolicy1" />

<!-- Uncomment the localhost url if you want to run the API locally -->
<!-- <add key="api:TaskServiceUrl" value="https://aadb2cplayground.azurewebsites.net/" /> -->
<add key="api:TaskServiceUrl" value="https://localhost:44332" />
<!-- <add key="api:TaskServiceUrl" value="https://localhost/TaskService" /> -->
<!-- <add key="api:TaskServiceUrl" value="https://elogic-ws.azurewebsites.net/TaskService/" /> -->

Single Sign out is not working

I have two .Net MVC applications where i have to mantain same session and end session on both apps on a single app getting signou, sometime its working fine locally but something is wrong when i published my app to azure. here is my code snippet as below

StartUpAuth:

public partial class Startup
{
    // App config settings
    public static string ClientId = ConfigurationManager.AppSettings["ida:ClientId"];
    public static string ClientSecret = ConfigurationManager.AppSettings["ida:ClientSecret"];
    public static string AadInstance = ConfigurationManager.AppSettings["ida:AadInstance"];
    public static string Tenant = ConfigurationManager.AppSettings["ida:Tenant"];
    public static string RedirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];
    public static string ServiceUrl = ConfigurationManager.AppSettings["api:TaskServiceUrl"];

    // B2C policy identifiers
    public static string SignUpSignInPolicyId = ConfigurationManager.AppSettings["ida:SignUpSignInPolicyId"];
    public static string EditProfilePolicyId = ConfigurationManager.AppSettings["ida:EditProfilePolicyId"];
    public static string ResetPasswordPolicyId = ConfigurationManager.AppSettings["ida:ResetPasswordPolicyId"];

    public static string DefaultPolicy = SignUpSignInPolicyId;

    // API Scopes
    public static string ApiIdentifier = ConfigurationManager.AppSettings["api:ApiIdentifier"];
    public static string ReadTasksScope = ApiIdentifier + ConfigurationManager.AppSettings["api:ReadScope"];
    public static string WriteTasksScope = ApiIdentifier + ConfigurationManager.AppSettings["api:WriteScope"];
    public static string[] Scopes = new string[] { ReadTasksScope, WriteTasksScope };

    // OWIN auth middleware constants
    public const string ObjectIdElement = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier";

    // Authorities
    public static string Authority = String.Format(AadInstance, Tenant, DefaultPolicy);

    /*
    * Configure the OWIN middleware 
    */
    public void ConfigureAuth(IAppBuilder app)
    {
        // Required for Azure webapps, as by default they force TLS 1.2 and this project attempts 1.0
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

        app.UseCookieAuthentication(new CookieAuthenticationOptions());

        app.UseOpenIdConnectAuthentication(
            new OpenIdConnectAuthenticationOptions
            {
                // Generate the metadata address using the tenant and policy information
                MetadataAddress = String.Format(AadInstance, Tenant, DefaultPolicy),

                // These are standard OpenID Connect parameters, with values pulled from web.config
                ClientId = ClientId,
                RedirectUri = RedirectUri,
                PostLogoutRedirectUri = RedirectUri,

                // Specify the callbacks for each type of notifications
                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    RedirectToIdentityProvider = OnRedirectToIdentityProvider,
                    AuthorizationCodeReceived = OnAuthorizationCodeReceived,
                    AuthenticationFailed = OnAuthenticationFailed,
                },

                // Specify the claim type that specifies the Name property.
                TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = "name"
                },

                // Specify the scope by appending all of the scopes requested into one string (separated by a blank space)
                Scope = $"openid profile offline_access {ReadTasksScope} {WriteTasksScope}"
            }
        );
    }

    /*
     *  On each call to Azure AD B2C, check if a policy (e.g. the profile edit or password reset policy) has been specified in the OWIN context.
     *  If so, use that policy when making the call. Also, don't request a code (since it won't be needed).
     */
    private Task OnRedirectToIdentityProvider(RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
    {
        var policy = notification.OwinContext.Get<string>("Policy");

        if (!string.IsNullOrEmpty(policy) && !policy.Equals(DefaultPolicy))
        {
            notification.ProtocolMessage.Scope = OpenIdConnectScope.OpenId;
            notification.ProtocolMessage.ResponseType = OpenIdConnectResponseType.IdToken;
            notification.ProtocolMessage.IssuerAddress = notification.ProtocolMessage.IssuerAddress.ToLower().Replace(DefaultPolicy.ToLower(), policy.ToLower());
        }

        return Task.FromResult(0);
    }

    /*
     * Catch any failures received by the authentication middleware and handle appropriately
     */
    private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
    {
        notification.HandleResponse();

        // Handle the error code that Azure AD B2C throws when trying to reset a password from the login page 
        // because password reset is not supported by a "sign-up or sign-in policy"
        if (notification.ProtocolMessage.ErrorDescription != null && notification.ProtocolMessage.ErrorDescription.Contains("AADB2C90118"))
        {
            // If the user clicked the reset password link, redirect to the reset password route
            notification.Response.Redirect("/Account/ResetPassword");
        }
        else if (notification.Exception.Message == "access_denied")
        {
            notification.Response.Redirect("/");
        }
        else
        {
            notification.Response.Redirect("/Home/Error?message=" + notification.Exception.Message);
        }

        return Task.FromResult(0);
    }


    /*
     * Callback function when an authorization code is received 
     */
    private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification notification)
    {
        // Extract the code from the response notification
        var code = notification.Code;

        string signedInUserID = notification.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
        TokenCache userTokenCache = new MSALSessionCache(signedInUserID, notification.OwinContext.Environment["System.Web.HttpContextBase"] as HttpContextBase).GetMsalCacheInstance();
        ConfidentialClientApplication cca = new ConfidentialClientApplication(ClientId, Authority, RedirectUri, new ClientCredential(ClientSecret), userTokenCache, null);
        try
        {
            AuthenticationResult result = await cca.AcquireTokenByAuthorizationCodeAsync(code, Scopes);
        }
        catch (Exception ex)
        {
            //TODO: Handle
            throw;
        }
    }
}`

Web.config
<add key="ida:Tenant" value="utilidexhub.onmicrosoft.com" /> <add key="ida:ClientId" value="****************************************" /> <add key="ida:AppExternalId" value="***********************************" /> <add key="ida:ClientSecret" value="-[y*******************%Uh" /> <add key="ida:AadInstance" value="https://login.microsoftonline.com/tfp/{0}/{1}/v2.0/.well-known/openid-configuration" /> <add key="ida:RedirectUri" value="https://********.azurewebsites.net" /> <add key="ida:HubUri" value="https://*********.azurewebsites.net" /> <add key="ida:UserValidationUri" value="https://utilidex-hub.azurewebsites.net/api/Admin/IsUserSubscribed" /> <add key="ida:SignUpSignInPolicyId" value="b2c_1_susi" /> <add key="ida:EditProfilePolicyId" value="b2c_1_edit_profile" /> <add key="ida:ResetPasswordPolicyId" value="b2c_1_reset" /> <!-- The following settings is used for requesting access tokens --> <add key="api:ApiIdentifier" value="https://utilidexhub.onmicrosoft.com/**Api/" /> <add key="api:ReadScope" value="read" /> <add key="api:WriteScope" value="write" />
AccountController:

public class AccountController : Controller
    {
        /*
         *  Called when requesting to sign up or sign in
         */
        public void SignUpSignIn()
        {
            // Use the default policy to process the sign up / sign in flow
            if (!Request.IsAuthenticated)
            {
                HttpContext.GetOwinContext().Authentication.Challenge();
                return;
            }

            Response.Redirect("/");
        }

        /*
         *  Called when requesting to edit a profile
         */
        public void EditProfile()
        {
            if (Request.IsAuthenticated)
            {
                // Let the middleware know you are trying to use the edit profile policy (see OnRedirectToIdentityProvider in Startup.Auth.cs)
                HttpContext.GetOwinContext().Set("Policy", Startup.EditProfilePolicyId);

                // Set the page to redirect to after editing the profile
                var authenticationProperties = new AuthenticationProperties { RedirectUri = "/" };
                HttpContext.GetOwinContext().Authentication.Challenge(authenticationProperties);

                return;
            }

            Response.Redirect("/");

        }

        /*
         *  Called when requesting to reset a password
         */
        public void ResetPassword()
        {
            // Let the middleware know you are trying to use the reset password policy (see OnRedirectToIdentityProvider in Startup.Auth.cs)
            HttpContext.GetOwinContext().Set("Policy", Startup.ResetPasswordPolicyId);

            // Set the page to redirect to after changing passwords
            var authenticationProperties = new AuthenticationProperties { RedirectUri = "/" };
            HttpContext.GetOwinContext().Authentication.Challenge(authenticationProperties);

            return;
        }

        /*
         *  Called when requesting to sign out
         */
        public void SignOut()
        {
            // To sign out the user, you should issue an OpenIDConnect sign out request.
            if (Request.IsAuthenticated)
            {
                IEnumerable<AuthenticationDescription> authTypes = HttpContext.GetOwinContext().Authentication.GetAuthenticationTypes();
                HttpContext.GetOwinContext().Authentication.SignOut(authTypes.Select(t => t.AuthenticationType).ToArray());
                Request.GetOwinContext().Authentication.GetAuthenticationTypes();
            }
        }
    }

Its really urgent for me, please reply with a solution...

Caching issuer and keys from the metadata endpoint

Hello all,

I've implemented the OpenIdConnectCachingSecurityTokenProvider but I'm wondering why all the time we need to make a call to retrieve the keys and the issuer from the metadata endpoint:

https://login.microsoftonline.com/{TENANT}.onmicrosoft.com/v2.0/.well-known/openid-configuration?p={POLICY}

As far as I know, the keys contains the public key that never changes and the issuer is always the same.

The only reason for get all the time the fresh value is that we change the B2C policy, right?

So, can we cache these values?

Feature request: Simplified sample project

Dear all,
First, thanks a mil for providing the sample application and the code-along sections attached to this project. The code-along sections helped a lot in the initial phase. However, what I did not quite grasp was why you decided to spread the sample application across multiple projects including making use of partial classes?
While the sample on its own is really great, I found it hard to apply the principles laid out in the sample to already existing projects that require implementation of Azure B2C features such as Login via Azure. I am currently struggling with such an undertaking (since an update via VS2019 using Connected Services failed).

Would it thus be possible to either provide a simplified version of the present project or maybe even an extra section describing how to add Azure B2C features to an existing solutions? I figure this would be beneficial to the community and to the project as such. I am sorry if this request is a lot to ask but being a beginner, I've been having difficulties once I completed the code-along section.

Please do not hesitate to get in touch in case my question is unclear (or in case I missed something, I haven't done much forum posting so far). I am looking forward to any reply. Thanks a mil in advance, kind regards.

IH

AAD Graph API calls from WEB API

Hi This is not an issue, Help required to read and modify AAD b2c user data from WEB API using AAD Graph API.
Could some one make a changes to this sample for my requirement.
Is there any other sample available for my scenario

OAuthBearerAuthenticationOptions in .NET 4.6 with Azure AD v2

Do you guys have a sample in .NET 4.6 or can give a pointer?

IIssuerSecurityTokenProvider is not longer available in Microsoft.Owin.Security.Jwt. There is now IIssuerSecurityKeyProvider and OpenIdConnectCachingSecurityTokenProvider is no longer compiling.

Therefore I cannot get OAuthBearerAuthenticationOptions working with an Azure AD v2 endpoint on my Web API.

Very outdated sample

These samples utilize an older version of Owin/microsoft identitymodel

What's the latest guidance on how to authenticate against B2C from a NON- aspnet core app?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.