Bad request while trying to get authToken using docusign API - docusignapi

I am new to docuSign API and I followed the code sample for C# in DocuSign guide site. I failed at the step while I was trying to get AuthToken. Part of my code as below, basically the same as the DocuSign sample,
public void OAuthAuthorizationCodeFlowTest()
{
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
// Make an API call with the token
ApiClient apiClient = new ApiClient(RestApiUrl);
DocuSign.eSign.Client.Configuration.Default.ApiClient = apiClient;
// Initiate the browser session to the Authentication server
// so the user can login.
string accountServerAuthUrl =
apiClient.GetAuthorizationUri(client_id, redirect_uri, true,
stateOptional);
System.Diagnostics.Process.Start(accountServerAuthUrl);
string accessToken = apiClient.GetOAuthToken(client_id,
client_secret, true, AccessCode);
// login call is available in the authentication api
AuthenticationApi authApi = new AuthenticationApi();
LoginInformation loginInfo = authApi.Login();
// parse the first account ID that is returned (user might belong to
multiple accounts)
AccountId = loginInfo.LoginAccounts[0].AccountId;
BaseUri = loginInfo.LoginAccounts[0].BaseUrl;
Console.WriteLine("accountId: " + AccountId);
Console.WriteLine("base_uri: " + BaseUri);
The client_id is my integrator key, the client_secret is the secret key related to that integrator key, right? I checked them many times, no problem. I am confused now why am I still getting 400 error. Please shed me some light here, thanks!!!

System.Diagnostics.Process.Start(accountServerAuthUrl); will open it on a browser, and once you have done successful authentication then browser will be redirected with the query parameter code=.... in the callback url (redirect_uri)
The code in browser needs to be read by your WEBApp, and then you need to call below code to generate the AccessToken:
string accessToken = apiClient.GetOAuthToken(client_id,
client_secret, true, AccessCode);
Below code is one part, to open the browser, ideally it is for testing purpose on a Standalone system, on a WEBApp you will redirect the browser to accountServerAuthUrl
public void OAuthAuthorizationCodeFlowTest()
{
// Make an API call with the token
ApiClient apiClient = new ApiClient(RestApiUrl);
DocuSign.eSign.Client.Configuration.Default.ApiClient = apiClient;
// Initiate the browser session to the Authentication server
// so the user can login.
string accountServerAuthUrl = apiClient.GetAuthorizationUri(client_id, redirect_uri, true, stateOptional);
System.Diagnostics.Process.Start(accountServerAuthUrl);
}
Below code is run when user is authenticated by the DocuSign on the browser and browser is redirected to the redirect_uri with code=..., your Webapp will read this code and send it as AccessCode and will call below code from your controller,
string accessToken = apiClient.GetOAuthToken(client_id, client_secret, true, AccessCode);

Related

Token management for ClientSecretCredential usage in MSGraph API

I need to send mails from a background application(worker service/azure function) using MSGraph API with Application permission. This is how I have initialized the GraphServiceClient to send emails.
var credentials = new ClientSecretCredential(
"TenantID",
"ClientId",
"ClientSecret",
new TokenCredentialOptions { AuthorityHost = AzureAuthorityHosts.AzurePublicCloud });
GraphServiceClient graphServiceClient = new GraphServiceClient(credentials);
var subject = $"Subject from demo code";
var body = $"Body from demo code";
// Define a simple e-mail message.
var email = new Microsoft.Graph.Message
{
Subject = subject,
Body = new ItemBody
{
ContentType = BodyType.Html,
Content = body
},
ToRecipients = new List<Recipient>()
{
new Recipient { EmailAddress = new EmailAddress { Address = "EmailId" }}
}
};
// Send mail as the given user.
graphServiceClient
.Users["UserID"]
.SendMail(email, true)
.Request()
.PostAsync().Wait();
How long the graphServiceClient will have a valid token and how to regenerate a token when the token is expired.
What are the best practices for this usage
The default lifetime of an access token is variable. When issued, an access token's default lifetime is assigned a random value ranging between 60-90 minutes (75 minutes on average). Please refer this DOC for more information.
The refresh tokens can be used to acquire access tokens if they expire, Refresh tokens are long-lived, and can be used to retain access to resources for extended periods of time.
For getting the access tokens with client secret please refer this method of getting the access tokens.
Hope this will help.
As of May 2022, there is no option to generate a refresh token while using client_credentials options.
For client_credentials option
It's possible to generate a refresh token while using on behalf of user
For on behalf of a user

DocuSign.eSign.Client.ApiException {"error":"consent_required"}" / Response Type Not Supported when attempting to grant consent

I tried to receive a token with the code below. Unfortunatelly I get the error:
DocuSign.eSign.Client.ApiException
HResult=0x80131500
Nachricht = Error while requesting server, received a non successful HTTP code with response Body: {"error":"consent_required"}
I tried with set TLS 12 and without. We run it in dev mode with base path https://demo.docusign.net/restapi
and oAuthBasePath =account-d.docusign.com
I tried also to set the consens manually with the URL below. But I receive the error in (Login Window) invalid Authorization: RequestType is not supported.
https://account-d.docusign.com/oauth/auth?response_type=code&scope=signature%20impersonation&client_id=a5ed47d5-xxxx-xxxx-8a19-756da64391de&redirect_uri=https://www.docusign.com
Is the something wrong with my account setting?
byte[] privateKey=DSHelper.ReadFileContent(DSHelper.PrepareFullPrivateKeyFilePath(privateKeyFilename));
var scopes = new List<string>
{
"signature",
"impersonation",
};
var basePath = ApiClient.Production_REST_BasePath;
var oAuthBasePath = OAuth.Production_OAuth_BasePath;
if (!production)
{
basePath = ApiClient.Demo_REST_BasePath;
oAuthBasePath = OAuth.Demo_OAuth_BasePath;
}
var _apiClient = new ApiClient(basePath);
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var authToken = _apiClient.RequestJWTUserToken(
clientId,
ImpersonatedUserId,
oAuthBasePath,
privateKey,
1,
scopes);
I found the solution. instead of reponse_type= code I have to use token
What response_type is supported for an integration key depends on how the key is configured. In the Authentication section of the key's configuration panel, Auth Code Grant allows the response type of code, while Implicit Grant allows the response type of token.
DocuSign's authentication docs assume you have "Auth Code Grant" selected, but either is technically acceptable to allow JWT consent.

How to query MS Graph API in User Context?

I'm trying to change a user's password using MS Graph API. I was checking earlier questions like this and this where the answer were always similar: register an AAD application, because changing the password requires Delegated
UserAuthenticationMethod.ReadWrite.All permissions, and you cannot set that in a B2C application as a B2C app supports only offline_access and openid for Delegated.
So the answers were always suggesting creating an AAD app, and using this app I could query the Graph API on behalf of the user. The question is, how to achieve this? If I check the documentation from Microsoft: Get access on behalf of a user, it is saying that first you need to get authorization, only then you can proceed to get your access token.
But as part of the authorization process, there is a user consent screen. If I'm calling my ASP.NET Core Web API endpoint to change my password on behalf of my user, how will it work on the server? The client won't be able to consent, if I'm doing these calls on the server, right?
Also, I'm using Microsoft.Graph and Microsoft.Graph.Auth Nuget packages and it's not clear how to perform these calls on behalf of the user. I was trying to do this:
var client = new GraphServiceClient(new SimpleAuthProvider(authToken));
await client.Users[myUserId]
.ChangePassword(currentPassword, newPassword)
.Request()
.PostAsync();
Where SimpleAuthProvider is just a dummy IAuthProvider implementation.
Any ideas how to make this work?
OK, got it:
static void ChangePasswordOfAUser()
{
var myAzureId = "65e328e8-5017-4966-93f0-b651d5261e2c"; // id of B2C user
var currentPassword = "my_old_pwd";
var newPassword = "newPassword!";
using (var client = new HttpClient())
{
var passwordTokenRequest = new PasswordTokenRequest
{
Address = $"https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token",
ClientId = clientId, // client ID of AAD app - not the B2C app!
ClientSecret = clientSecret,
UserName = $"{myAzureId}#contoso.onmicrosoft.com",
Password = currentPassword,
Scope = "https://graph.microsoft.com/.default" // you need to have delegate access
};
var response = client.RequestPasswordTokenAsync(passwordTokenRequest).Result;
var userAccessToken = response.AccessToken;
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {userAccessToken}");
var json = System.Text.Json.JsonSerializer.Serialize(new
{
currentPassword = currentPassword,
newPassword = newPassword
});
var changePasswordResponse = client.PostAsync(
$"https://graph.microsoft.com/v1.0/users/{myAzureId}/changePassword",
new StringContent(json, Encoding.UTF8, "application/json"))
.Result;
changePasswordResponse.EnsureSuccessStatusCode();
}
}

Google OAuth flow - passing the resulting tokens via querystring

I'm reviewing some code that uses the OpenIdConnect OAuth flow in asp.net core to auth a user against Google. Once auth is established, there is a handler in OnTicketRecieved that takes the resulting access token and refresh token, and passes that to a different endpoint in the app:
OnTicketReceived = context =>
{
string returnUrl = "/Somewhere/else";
string refreshToken = context.Properties.Items.ContainsKey(".Token.refresh_token") ? context.Properties.Items[".Token.refresh_token"] : "none";
string accessToken = context.Properties.Items.ContainsKey(".Token.access_token") ? context.Properties.Items[".Token.access_token"] : "none";
var email = context.Principal.Claims.Where(c => c.Type == ClaimTypes.Email).Select(c => c.Value).SingleOrDefault();
returnUrl += $"?refreshToken={refreshToken}&accessToken={accessToken}&email={email}";
context.ReturnUri = returnUrl + WebUtility.UrlEncode(returnUrl);
return Task.CompletedTask;
},
My question is - how secure is this? It's effectively leaking refresh tokens that can be seen - although the scope of what you can do with them is very limited, being Google OAuth we're locked down to endpoints we can interact with, and the app secret would also need to be known in order to do anything malicious with these tokens
Thanks
Matt

Identity 2.0 After Login go to Infinite Loop asp.net mvc 5

I have added email confirmation process like below:
var code = await _users.GenerateEmailConfirmationTokenAsync(model.UserName);
var callbackUrl = Url.Action(
"ConfirmEmail", "Account",
new { username = model.UserName, code = code },
protocol: Request.Url.Scheme);
then confirm email with below code:
public async Task ConfirmationEmailAsync(CmsUser user, string token)
{
var provider = new DpapiDataProtectionProvider(WebConfigurationManager.AppSettings["AppName"].ToString());
_manager.UserTokenProvider = new DataProtectorTokenProvider<CmsUser>(
provider.Create("EmailConfirmation"));
await _manager.ConfirmEmailAsync(user.Id, token);
}
after that I will login it will go to infinite loop.
http://localhost:3214/account/login?ReturnUrl=%2Faccount%2Flogin%3FReturnUrl%3D%252Faccount%252Flogin%253FReturnUrl%253D%25252Faccount%25252Flogin%25253FReturnUrl%25253D%2525252Faccount%2525252Flogin%2525253FReturnUrl%2525253D%252525252Faccount%252525252Flogin%252525253FReturnUrl%252525253D%25252525252Faccount%25252525252Flogin%25252525253FReturnUrl%25252525253D%2525252525252Faccount%2525252525252Flogin%2525252525253FReturnUrl%2525252525253D%252525252525252Faccount%252525252525252Flogin%25252525252525...
Here, I have calling below method:
public async Task<string> GenerateEmailConfirmationTokenAsync(CmsUser user)
{
var provider = new DpapiDataProtectionProvider(WebConfigurationManager.AppSettings["AppName"].ToString());
_manager.UserTokenProvider = new DataProtectorTokenProvider<CmsUser>(
provider.Create("EmailConfirmation"));
return await _manager.GenerateEmailConfirmationTokenAsync(user.Id);
}
The problem is not about your Generate EMail action. It is about your authentication.
Probably, your Login action in Account controller is requiring authorization. For instance, you can have AuthorizeAttribute on an action or a controller. Maybe, it's a global filter or something's wrong with Web.config.
Anyway, that's what actually happens:
User tries to access your Generate EMail method
He is unauthorized. Then, he is redirected to Account / Login method.
This method requires authorization. Goto 2.
You need to review your authentication, debug it and find the basic problem before you continue implementing your EMail confirmation.

Resources