I am trying to generate a token for a user with below code.
string apiResourceId = "11224320-66b9-4132-8953-9aa485f07004";
string clientId = "bc9869a0-2393-4e42-8c52-845071640ea8";
Uri redirectUri = new Uri("https://localhost:44335/");
string authority = string.Format("https://login.windows.net/{0}",
"rudderless.onmicrosoft.com");
var authContext = new AuthenticationContext(authority);
AuthenticationResult authenticationResult;
authenticationResult = await authContext.AcquireTokenAsync(apiResourceId, clientId,
redirectUri, new PlatformParameters(PromptBehavior.Auto, null));
I have been getting an error in AcquireTokenAsync call -
AADSTS70002: The request body must contain the following parameter:
'client_secret or client_assertion'. Trace ID:
a198696d-8377-40eb-8351-527a25183500 Correlation ID:
24d4b47d-67bf-46c0-a6b7-a248c434512e Timestamp: 2017-09-20 23:09:38Z
Why do I need a client_secret or client_assertion if I want to generate a token when a user is authenticated against a AAD? The type of Client I am using is "Web app /API". However when I am trying to use a Native client I get the token generated but API call to apResourceID is generating unauthorized error.
Few Questions I am seeking help on related to the scinario -
Why I need to provide client_secret when I am using user auth flow?
Why AcquireToken succeed when I change the client Type to Native?
Why the token generated through native client gives an Unauthorize error?
Is there a way for admin to consent on behalf of every user in AAD?
Why I need to provide client_secret when I am using user auth flow?
Web Apps and APIs are considered Confidential Clients. See here for a definition of the different Client Types in the OAuth 2 Specification. These kinds of client always need to use their client secret to authenticate, no matter the flow they are following.
Confidential clients are typically issued (or establish) a set of
client credentials used for authenticating with the authorization
server (e.g., password, public/private key pair).
Why AcquireToken succeed when I change the client Type to Native?
Native Client Applications are a subset of Public Clients. These are defined, in the specification as:
Clients incapable of maintaining the confidentiality of their
credentials (e.g., clients executing on the device used by the
resource owner, such as an installed native application or a web
browser-based application), and incapable of secure client
authentication via any other means.
Therefore, they do not have or need a client_secret to authenticate... but this also means they can only authenticate with user context, whereas a confidential client could authenticate without a user present (Client Credential Flow).
Why the token generated through native client gives an Unauthorize
error?
This is hard to answer without knowing more about the error and the call you are making that causes this error. You should provide more information about this scenario.
Is there a way for admin to consent on behalf of every user
in AAD?
Yes. In the new Azure Active Directory V2 Endpoint, we have an "Admin Consent Endpoint".
Using the older V1 endpoint, we have an &prompt=admin_consent query string which you can read about here.
Related
I want, when user login he should get list of tenant, from that list, user decide in which tenant he want to redirect
I want to call https://graph.microsoft.com/v1.0/organization API but when I write code to call it , it will returned error, I have get token using below code, it is worked for users API of Graph, but not working for organization api
B2BGraphClient.AccessToken = await authContext.AcquireTokenAsync("https://graph.microsoft.com/", credential).ConfigureAwait(false);
I have checked it using Postman, when I have pass token generated using https://login.microsoftonline.com/common/oauth2/token this api, organization api returns correct output, but logically it is not possible in code to pass userid and password to api and get token, below is image of postman call
I want correct way to do this
Your code is using Client_credentials flow but in Postman you are using ROPC flow.
The two flows use different permission type. Client_credentials flow uses Application permission while ROPC flow uses Delegated permission.
So for Client_credentials flow, if the app belongs to a work or school (organization) context then for https://login.microsoftonline.com/common/oauth2/token replace common with a tenantId or domain name. If you don't do this, you will get the Authorization_IdentityNotFound error.
Specify the tenant in the code (modify the sample code based on your needs).
this.clientId = clientId;
this.clientSecret = clientSecret;
this.tenant = tenant;
// The AuthenticationContext is ADAL's primary class, in which you indicate the direcotry to use.
this.authContext = new AuthenticationContext("https://login.microsoftonline.com/" + tenant);
// The ClientCredential is where you pass in your client_id and client_secret, which are provided to Azure AD in order to receive an access_token using the app's identity.
this.credential = new ClientCredential(clientId, clientSecret);
B2BGraphClient.AccessToken = await this.authContext.AcquireTokenAsync("https://graph.microsoft.com/", this.credential).ConfigureAwait(false);
And don't forget to add one of the following Application permissions Organization.Read.All, Directory.Read.All, Organization.ReadWrite.All, Directory.ReadWrite.All in your app registration as per Permissions.
UPDATE:
In fact this endpoint https://graph.microsoft.com/v1.0/organization can't return the tenants which the user is member of.
You have found the correct Azure rest API to list the tenants.
But this API also doesn't support client_credentials flow.
In another word, you cannot use authContext.AcquireTokenAsync to get the token. You should consider AcquireTokenByAuthorizationCodeAsync. And specify the scope as https://management.azure.com/ instead of https://graph.microsoft.com.
Don't forget to add the Azure Rest permission in app registration.
In JWT from AAD there is a key 'aud'. https://jwt.io/, says it is 'Audience. (Who or what the the token is intended for)'. My question is, Are aud values website specific - can I check the aud and expect it to be same to check if the token is intended for my specific site?
In Azure AD, the audience value always indicates the resource the token is targeted on.
You can acquire an access token by using either the API's client id or Application ID URI.
What you use will be the audience in the token.
So if you make an API, you should check the audience is either the API's client id or Application ID URI.
You can know for sure it will always be one of those if the token is meant for your API.
EDIT: The below information is not correct.
If I know your API's identifier + your tenant id,
I can acquire an access token for your API using client credentials!
The token will not contain scopes or roles, it cannot.
So it is critical that you check for the presence of valid delegated permissions (aka scopes) or valid app permissions (in roles claim).
THIS IS WRONG: If I tried to acquire an access token using your API's identifier from my AAD tenant, it would not give me a token.
Any app that passes an access token with the correct audience had rights to call your API when it acquired the token.
You already got a good explanation of the audience value from juunas.
I'm adding here a specific code example from Azure-Samples on Github which shows how to validate the JWT Token manually and checks among other things audience value. (It's pretty important to validate issuer as well)
Look at this particular code and especially near the comment "We accept both the App Id URI and the AppId of this service application"
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
TokenValidationParameters validationParameters = new TokenValidationParameters
{
// We accept both the App Id URI and the AppId of this service application
ValidAudiences = new[] { audience, clientId },
// Supports both the Azure AD V1 and V2 endpoint
ValidIssuers = new[] { issuer, $"{issuer}/v2.0" },
IssuerSigningKeys = signingKeys
};
Code Sample:
Specific file with code excerpt shown above
Azure-Samples: Manually validating a JWT access token in a web API
I am writing code to use docusign demo machine through Docusign.esign.dll . I have tried using Oauth process for connecting the docusign.
I have used the code similar to the code motioned in here.
https://github.com/docusign/docusign-csharp-client/blob/master/test/SdkTests/JwtAuthUnitTests.cs
But I have used my demo machine Integetor key and private key. But I am getting the below error. So do I need to change any setup in my demo machine? Or how do I get valid Integotor key.
I hope my PEM key is causing the issue. So let me know how to preparte that pEM KEy.
I just copied by Private key and created the PEM file using notepad application.
Please let me know do I miss any thing?
Error calling Login: {\r\n \"errorCode\": \"PARTNER_AUTHENTICATION_FAILED\",\r\n \"message\": \"The specified Integrator Key was not found or is disabled. An Integrator key was not specified.\"\r\n}"}
BY default, the API points to their live/production servers. After creating an instance of the ApiClient, set it to point at the demo server:
apiClient.RestClient.BaseUrl = new Uri("https://demo.docusign.net/restapi");
Edit: That was for legacy authentication. For OAuth, please check to make sure you're pointing to account-d.docusign.com (notice the -d).
I too found this to be the issue, in the response the bearer token is missing
<br/><br/>string host = "https://demo.docusign.net/restapi/v2";
// Note with or without v2 their supplied credentials work<br/>
string oauthBasePath = "account-d.docusign.com";<br/>
ApiClient apiClient = new ApiClient(host);<br/>
apiClient.ConfigureJwtAuthorizationFlow(integratorKey, userId, oauthBasePath, privateKeyFilename, expiresInHours);
When you use the credentials from the JwtAuthUnitTests - TestConfig all works
Steps followed should be:
Created demo machine
Created IK
Created Secret key
Created RSA pair key
Copy the private key in to notepad and save that file in location
Missing steps are:
Granting Consent either using User Consent or Admin Consent, check
Service Integration for details.
Configure Redirect URI in the Integrator Key, only needed for User
Consent via Authorization Code Grant
You can use Admin Consent only if you can claim email domain in DocuSign else you need to use User Consent. With User Consent, normally using Authorization Code Grant, you need to get consent with scopes of Impersonation Signature. Once you have user's consent, then you can get new AccessToken for that user using JWT.
Also you need to point to correct host for Demo and Prod,
account-d.docusign.com is required for Demo
account.docusign.com is required for Prod
Above host is used to get access token from DocuSign Account Server (/oauth/token), and you will use above host also for getting the baseUri from /oauth/userinfo endpoint. Other than these two call, I don't think you will use above host.
In response for /oauth/userinfo endpoint call, you will get base_uri and account_id like below
"account_id": "fe0b61a3-3b9b-cafe-b7be-4592af32aa9b"
"base_uri": "https://demo.docusign.net"
You will use above base_uri and account_id for any other API calls, like for creating envelope etc
<base_uri>/restapi/v2/accounts/<account_Id>/envelopes
A native app created which is calling web api.Two apps has been created in the azure.Here is the code code for getting access token and it worked well,I am getting access token:
UserCredential uc = new UserPasswordCredential(userName, password);
result = authContext.AcquireTokenAsync(todoListResourceId,clientId,
uc).Result;
Now to access new token after the expiry of old one(1 hr) i am using the code:
AuthenticationContext authContext = new AuthenticationContext(authority);
UserAssertion userAssertion = new UserAssertion(oldToken, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
AuthenticationResult result = authContext.AcquireTokenAsync(todoListResourceId, clientId, userAssertion).ConfigureAwait(false).GetAwaiter().GetResult();
But I am getting Error as:"Invalid JWT token. AADSTS50027: Invalid JWT token. Token format not valid".
Checked JWT token :it is correct in format can able to decode using jwt.io.
Note: client Id am using for these two code snippet are the same appId.
I know this is the exact duplication of the question asked by devangi.I cannot able to comment on that question that's why I am asking it again.
Any one can able to help me out?
Or
It will be great if any one can able to help with other ways to get token with out using user password since i need to internally generate new token without user enter password again.
For the scenario when user has authenticated on a native application, and this native application needs to call a web API. Azure AD issues a JWT access token to call the web API. If the web API needs to call another downstream web API, it can use the on-behalf-of flow to delegate the user’s identity and authenticate to the second-tier web API .
Please refer to this document for more details about On-Behalf-Of flow . You can also refer to code sample .
For the scenario when when a daemon application(Your web api) needs to call a web API without user's identity , you should use client credential flow to use its own credentials instead of impersonating a user, to authenticate when calling another web service. Code sample here is for your reference .
Please click here for explanation about above two scenarios. Your code is using Resource Owner Password Credentials Grant ,this flow has multi restrictions such as don't support 2FA and is not recommended .
If i misunderstand your requirement , please feel free to let me know .
Need help in authenticating the token request from any client application to WEB API. We have registered our web API has multi-tenant application in Azure AAD. My client application which has been registered in different tenant was able to get Access token from AAD.while making Http request to our endpoint with passing the access token part of request header, we are receiving 401 unauthorized exception. I found reason while browsing for multi tenant scenario is to disable ValidateIssuer and have custom handler.
• Is there any custom handler on implementing for WindowsAzureActiveDirectoryBearerAuthentication. I see people are using OpenIDConnect. But for WEB API, we are using WindowsAzureActiveDirectoryBearerAuthentication i.e Is there any equivalent Event for validation of access token in UseWindowsAzureActiveDirectoryBearerAuthentication and tell user is authenticated ?.
• Is there any better standard of validation of access token and tell user is valid user ?.
• Can we get the claims of user by passing bearer token to WEBAPI Authorize filter ?. or will httprequest object claims gets user information like given name, tenant name, object ID (esp. localhost debugging scenario also.), If we can get those information, we can have our own logic of validation.
Please let us know whether this approach is best practice for authenticating a user.
You could implement a custom issuer validator and assign it to the IssuerValidator property. This is useful when you can't specify a predefined list of issuers in configuration and need some runtime logic to determine if you trust the issuer presented in the token:
TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
{
IssuerValidator = (issuer, token, tvp) =>
{
if (db.Issuers.FirstOrDefault(b => (b.Issuer == issuer)) == null)
return issuer;
else
throw new SecurityTokenInvalidIssuerException("Invalid issuer");
}
}
You could decode the access token to get basic user information like family_name/given_name , but you can only get that by using user identity to acquire the access token .