I am using OpenID Connect to connect to Azure ID, I can successfully authenticate in Azure and get the request coming back to the redirect uri specified in OpenID Azure AD Configuration.
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
AuthenticationType = " TEST",
Caption = "Test Azure AD",
SignInAsAuthenticationType = signInAsType,
ClientId = "<client ID>",
Authority = "https://sts.windows.net/<tenantId>",
ResponseType = OpenIdConnectResponseTypes.CodeIdToken,
RedirectUri = "https://localhost:44392/External/Login", This is another webapi project, not identityserver host.
AuthenticationMode = AuthenticationMode.Passive,
});
After succesful authentication it is redirecting back to https://localhost:44392/External/Login with Code, IdToken.
Questions :
Does it not stop at AuthenticateExternalAsync method on redirection unlike google-signin ?
Do i have to decode IdToken JWT to get user claims?
In the redirection method, how do i generate Access Token from IdSrv3 to authorize other webapis ?
Can a user have both Local Login and Multiple External logins ( Azure AD, Google etc ). In this case how does SSO works with IDsrv3 ?
Is there any IdSrv3 sample with External logins implemented ? Preferably Azure AD ?
I've just struggled through this process, so I'll attempt to answer as best I can to help you/others. Forgive me if I misunderstand your question.
AuthenticateExternalAsync should be called, but you need to have AzureAd return to the IDS (Identity Server) rather than to your App. Your flow should look something like: app -> IDS -> AzureAd -> IDS (AuthenticateExternalAsync) -> App.
In AuthenticateExternalAsync you get the ExternalAuthenticationContext.ExternalIdentity, which contains the claims - no need to decode the JWT token.
IDS handles this once you return a successful AuthenticatedResult in AuthenticateExternalAsync, something like context.AuthenticateResult = new AuthenticateResult("UserId", name, claims);
Yes. You can force the method of logging in as described for SSO purposes, otherwise I imagine IDS would handle it post first-login.
I found this helpful (runs through setup of IDS and AzureAd), but it does use the old Azure Portal rather than the new one. They don't seem to have any samples in their gallery.
Hope that helps a bit :)
Related
Needing help from anyone.
I have a SPA client application that is talking to a WebApi (.Net 4.52). Both have been developed by my company. It has been working quite fine with tokens that the WebAPI has been generating itself (based on the excellent articles from bitoftech)
We now want to allow authentication with Azure - more specifically, my customer's own azure tenant (which I have no direct control over). To do this on the client-side, we use adal.js to do the back and forth with actually signing the user in, and we use UseWindowsAzureActiveDirectoryBearerAuthentication on the server-side to validate the azure tokens.
The Oauth startup looks like this:
public static void RunAcademyOAuthStartup(IAppBuilder app)
{
if (ConfigurationManager.AppSettings["ida:Enabled"] == "1")
{
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
{
ValidAudience = ConfigurationManager.AppSettings["ida:Audience"],
AuthenticationType = "ExternalAzureSSO"
},
Tenant = ConfigurationManager.AppSettings["ida:Tenant"]
}
);
}
var apiAccessTokenLifeTimeSeconds = 0;
if (!int.TryParse(ConfigurationManager.AppSettings["ApiAccessTokenLifetimeSeconds"], out apiAccessTokenLifeTimeSeconds))
{
apiAccessTokenLifeTimeSeconds = 1800; //set default to 30 minutes
}
var oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/api/user/authenticate"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(apiAccessTokenLifeTimeSeconds),
Provider = new SimpleAuthorizationServerProvider(),
RefreshTokenProvider = new SimpleRefreshTokenProvider(),
AuthenticationType = "LocalApplication"
};
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
// Token Generation - setup the token authorization server
app.UseOAuthAuthorizationServer(oAuthServerOptions);
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
}
The code above is no different to hundreds of other examples I've been trawling through for days.
This all works fine when I use my free Azure instance (through my company's MSDN) - I can authenticate, the token comes back from azure, webapi can decode it and validate and it continues on.
My problem arises when I try this against my customer's P1 Azure instance - I can authenticate, get a token back, but my webapi does not decode the token. There is no errors logged as far as I can see.
The main thing I can see at the moment is when I get the azure token and decode it using jwt.io, I can see the "x5t" and "kid" values. Based on other information I have found around the 'net, I should be able to get the latest keys from https://login.microsoftonline.com/common/discovery/keys and find either the "x5t" and/or the "kid" values in there....but I can't.
Is this possible? What would cause a token to be generated with keys other than the common ones? Is this a configuration item within the app registration in azure? Do I need to add more settings to the UseWindowsAzureActiveDirectoryBearerAuthentication config in web api?
Tokens are all v1
An answer for anyone who is coming across this thread in the future...probably a rookie mistake :)
What I found in my case was that the admin on the Azure side had registered my application using the "Enterprise Applications" option in their Azure Portal BEFORE editing the manifest,etc in the "App Registrations" area. According to Microsoft Support, it should be done the other way around - register in App Registrations first, then go to Enterprise Applications (if needed). Doing things in that order means that the azure tenant then generates the tokens and signs them with the "common" keys, and not the custom key that a Enterprise App gets.
I'm having hard times trying to use Azure AD B2C to authenticate My Web API.
I'll start with some background
I created mobile application which is using Azure AD B2C to authenticate users. I'm creating a WebView which display this url:
User is asked to login to azure ad, if the login data is successfull i'm receiving a response containing the access token - this part went smooth, everything works properly.
Now i want to create backend Web Api. I created ASP NET Core Web application which allows me to choose authentication method. I choose the Azure AD authentication so the template generated all required data for me. The relevant part in the code is here:
I updated all required config properties to match my azure settings. At this point i would expect to be able to call the API using access token i received on the mobile app. I run mobile app locally, signed in, received access token, copied it and tried to call my web api(hosted in IIS express) using postman ( with authorization header "Bearer ..." ). Unfortunately with no luck - i'm receiving 401 with following header:
Bearer error="invalid_token", error_description="The signature key was
not found"
I thought token is enough to Authorize the API - i understand this is a whole point of OAuth. Am i missing something ? Should i have some additional config ? I Noticed the config is missing the sign in policy ( which seems to be required by AD B2C name so i tried adding that:
var validationParameters = new TokenValidationParameters
{
AuthenticationType = "MY_POLICY",
};
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
Authority = Configuration["Authentication:AzureAd:AADInstance"] + Configuration["Authentication:AzureAd:TenantId"],
Audience = Configuration["Authentication:AzureAd:Audience"],
TokenValidationParameters = validationParameters
});
But this didn't work too. Will appreciate any help.
EDIT
I found following error in Visual Studio logs:
Bearer was not authenticated. Failure message: IDX10501: Signature
validation failed. Unable to match 'kid': '...'
#juunas comment help me to find the issue. I inspected outgoing requests with fiddler and i found that with this piece of code:
Authority = Configuration["Authentication:AzureAd:AADInstance"] + Configuration["Authentication:AzureAd:TenantId"]
The request was being send to following address:
https://login.microsoftonline.com/MYTENANTID/.well-known/openid-configuration
There are two issues with above:
It's not using v2 endpoint. Proper link for B2C should always use v2 so it would look like:
https://login.microsoftonline.com/MYTENANTID/v2.0/.well-known/openid-configuration
It was not adding sign in policy to the link ( even if i set it in token options )
I managed to make it work with removing "Authority" parameter and changing the configure auth function to following:
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
MetadataAddress = string.Format("https://login.microsoftonline.com/{0}/v2.0/.well-known/openid-configuration?p={1}",
Configuration["Authentication:AzureAd:TenantId"], "MYPOLICY"),
AuthenticationScheme = "MYPOLICY",
Audience = Configuration["Authentication:AzureAD:ClientId"],
});
I am using OWIN OpenID Connect Middleware to connect to Azure AD. I am able to authenticate the user successfully and redirect back to callback endpoint. I am a bit confused here as i am receiving only id_token & code in the response.
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
AuthenticationType = "Azure AD - TEST",
Caption = "azure AD",
SignInAsAuthenticationType = signInAsType,
ClientId = "some guid",
Authority = "https://sts.windows.net/idp",
ResponseType = OpenIdConnectResponseTypes.CodeIdToken,
RedirectUri = "https://localhost:44392/ExternalLogins/Callback/",
AuthenticationMode = AuthenticationMode.Active,
});
Callback Method :
[HttpPost]
[Route("ExternalLogins/Callback")]
[AllowAnonymous]
public async Task<IHttpActionResult> ExternalLoginCallback()
{
var content = await Request.Content.ReadAsStringAsync();
// I could see the content is a string with id_token, code , state etc.
//id_token is a JWT, so i can decode it and see the user claims and use them later
}
My Questions are :
Is Azure AD used for only authenticating the user ? What about authorizatoin ?
If i want to make calls to other APIs after authentication, how do i do that as i don't have access_token ?
I think i can exchange code with access_token but not sure which Azure endpoint i need to call to get access_token ?
What is the difference between AuthenticationMode.Active and AuthenticationMode.Passive ?
Azure AD can absolutely authorize a user and get your Access/Refresh tokens. It supports all oAuth 2.0 and OIDC flows.
You'll need to get an access token to make calls to an api. Let's say you want to call a /get endpoint on the MS Graph, you will stuff the access token into the body of the http request with the keyword Bearer ey... in front of it.
Additionally, you'll need to go into the Azure Portal and configure the delegated permissions you want to access.
The auth code is used to exchange for the access_token. I suggest checking out this protocol doc that shows you how to use all the endpoints. The short answer is you POST to the /token endpoint.
The difference between active and passive is a bit complex for a SO answer, I recommend reading this blog post about the differences.
I'll just add that if you want to see some sample code using Azure AD you can go to Azure AD Dev Guide or Azure AD code samples on Github.
I am using MSAL to connect my Xamarin.Forms-Windows 8.1-App to Azure AD B2C with a custom SignInSignUp-policy (to login the user by using a custom E-Mail address and a password). The "normal" authentication against Azure AD (without custom policy) works fine, but when I use the policy, the message "We can't connect to the service you need right now. Check your network connection or try this again later." appears everytime after providing the credentials (directly within the dialog). Since the dialog does not finish correctly, I am not retrieving any exception or AuthenticationResult and so I am not able to determine the concrete issue (the internet connection itself is not the problem).
Note: I also tried this in a Xamarin.Forms-UWP-App which leads me to the same issue. Under iOS, it is working fine and the dialog finishes and closes correctly.
NuGet Versions:
MSAL (Microsoft.Identity.Client): 1.0.304142201-alpha
Xamarin.Forms: 2.3.2.118-pre1
Thats my code (simplified):
var clientId = "{My application's ClientId}";
var redirectUri = "urn:ietf:wg:oauth:2.0:oob";
var authority = "https://login.microsoftonline.com/{My Azure AD B2C}";
string[] scopes = { clientId };
var policy = "{My SignUpSignIn policy}";
var clientApplication = new PublicClientApplication (authority, clientId);
clientApplication.RedirectUri = redirectUri;
var result = await this.clientApplication.AcquireTokenAsync(scopes, string.Empty, UiOptions.SelectAccount, string.Empty, null, authority, policy);
Any ideas on this?
Thanks in advance!
Regards,
Marcel
I had the same issue. Turns out I forgot to properly set up my mobile app to allow loggin in via Active Directory
The steps I took that solved my problem were:
In Azure B2C Blade select Application and set the Reply URL to the address of the Azure Mobile Apps instance (e.g. https://myapp.azurewebsites.net), followed by /.auth/login/aad/callback
Make sure the policies used in the Azure Active Directory B2C tenant should be configured so that the Reply URL is set to the same as above
In the Azure Mobile or Services App go to settings-->authentication/autorization and make sure that a non authenticated request is set up to log in with AAD
in the same blade select the AAD provider, go to advanced and set up Client ID and Issuer URL, with the Client ID being the Application ID of the Azure Active Directory B2C tenant, and the Issuer Url being the Metadata Endpoint for the Azure Active Directory B2C policy
Once I did the above all worked flawlessly.
More detailed instructions can be found at https://developer.xamarin.com/guides/xamarin-forms/web-services/authentication/azure-ad-b2c-mobile-app/
Let me know if this helped...
I have configured my Web application to use Azure Auth logon. Everything works fine and users can logon if they're not already logged on to Azure.
My issue is that when a user is already logged into Azure of Office 365 and they browse to my site, they get this error below. I understand what the error means, but I want to know if there is a way to redirect to another URL (on my site) if this issue occurs. Here is that error:
This is my startup code for configuring OpenId Auth:
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions {
ClientId = Configuration.clientID,
Authority = authenticationAuthority,
PostLogoutRedirectUri = Configuration.logoutRedirectURL,
Notifications = new OpenIdConnectAuthenticationNotifications {
AuthenticationFailed = context => {
context.HandleResponse();
context.Response.Redirect("/Unauthorised.aspx?message=" + context.Exception.Message);
return Task.FromResult(0);
}
}
});
There are a couple of ways around this, depending on your scenario.
If you want to authenticate them using their existing credentials, you can enable multi-tenant support in your application's registration. This will allow an external user to authenticate with your application using their own AAD credentials rather than one in your AAD tenant.
If you need to force them to reauthenticate using your credentials, you can add prompt=login to your initial Authorization URI (https://login.microsoft.com/{tenant}/oauth/authorize?...&prompt=login). This will force the user to authenticate against your application, even if they already have an active authentication cookie (in most cases "authenticate" here simply means that the user will need to select an account from a list, not re-enter id & password).