Create Envelope with access token returns 404 (DocuSign PHP SDK) - docusignapi

I am trying to create an envelope through PHP sdk, we have working integration using X-DocuSign-Authentication header (with user, password, integrator key combo). Trying to migrate the integration to access token, but keep on getting 404 Resource not found error from the actual SDK (the resources is dictated by the SDK).
Current code:
// DocuSign\eSign\Configuration
$config = new Configuration();
$config->setHost('https://www.docusign.net/restapi');
// DocuSign\eSign\Client\ApiClient
$api = new ApiClient($config);
try {
$response = $api->requestJWTUserToken(
"correct-integrators-key",
"correct-user-id",
file_get_contents( base_path() . '/ds-private.key', true), //exists
"signature impersonation",
);
}
catch (ApiException $e) {
return $e->getMessage();
}
JWT Token payload comes back successfully, and access token is valid.
// DocuSign\eSign\Client\Auth\OAuthToken
if(!$response[0] instanceof OAuthToken)
return "Auth Token Invalid.";
$access_token = $response[0]->getAccessToken();
try {
$user = $api->getUserInfo($access_token);
} catch (ApiException $e) {
return $e->getMessage();
}
// DocuSign\eSign\Client\Auth\UserInfo
if(!$user[0] instanceof UserInfo)
return "User Info Invalid.";
Setting the account ID and base URL also are seemingly correct (account ID comes back as expected, and is correct one, base URL comes back as na2 subdomain, seems to be the correct - this is supported by the fact that "USER_DOES_NOT_BELONG_TO_SPECIFIED_ACCOUNT" is thrown if any other host is used)
$account_id = null;
$base_url = null;
foreach ($user[0]->getAccounts() as $account) {
if($account instanceof Account)
if($account->getIsDefault()) {
$account_id = $account->getAccountId(); // Account ID succeeds, comes back as correct account ID (verified on the admin panel)
$base_url = $account->getBaseUri(); // Base URL succeeds, comes back as na2 subdomain
}
}
$config->setAccessToken($access_token); // Access token succeeds
$config->setHost($base_url);
This code is practically copy/paste of working example with the "old" integration.
$envelopeApi = new EnvelopesApi($api);
$templateRole = new TemplateRole();
$definition = new EnvelopeDefinition();
$templateRole->setEmail('catchable#gmail.com');
$templateRole->setName('Rebecca Smith');
$templateRole->setRoleName('Correct Role Defined On Template');
$templateRole->setClientUserId('Correct User Id For Embedding');
$signers = [];
$signers[] = $templateRole;
$definition->setTemplateId('Valid Template Id');
$definition->setTemplateRoles($signers);
$definition->setStatus('sent');
try {
$envelope = $envelopeApi->createEnvelope($account_id, $definition);
}
catch (ApiException $e) {
return [
'envelope_error_message' => $e->getMessage(), // Returns: "Error while requesting server, received a non successful HTTP code [404] with response Body: "
'envelope_error_code' => $e->getCode(), // Returns: 404
];
}
Tried also directly running $api->callApi to check if v2.1 vs v2 in resource path is the issue, but got 404 on both.

You need to append /restapi to the baseUri
Instead of
$base_url = $account->getBaseUri(); // Base URL succeeds, comes back as na2 subdomain
try
$base_uri_suffix = '/restapi';
$base_url = $account->getBaseUri().$base_uri_suffix; // Base URL succeeds, comes back as na2 subdomain
See the source in the PHP Code Example

Related

Instagram Basic Display API Error - Invalid scope: ['basic'] OR Invalid redirect_uri

I'm using Magento 2.4.1, installed Social Login Extension and getting below error while login to Instagram, I'm using Hybrid auth libraries to login.
"error_type": "OAuthException", "code": 400, "error_message": "Invalid
scope: ['basic']"}
You can check the screenshot below,
Instagram.php
<?php
/*!
* HybridAuth
* http://hybridauth.sourceforge.net | https://github.com/hybridauth/hybridauth
* (c) 2009-2012 HybridAuth authors | http://hybridauth.sourceforge.net/licenses.html
*/
namespace Vendor\Module\Model\Providers;
/**
* Hybrid_Providers_Instagram (By Sebastian Lasse - https://github.com/sebilasse)
*/
class Instagram extends \Hybrid_Provider_Model_OAuth2
{
// default permissions
public $scope = "basic";
/**
* IDp wrappers initializer
*/
public function initialize()
{
parent::initialize();
// Provider api end-points
$this->api->api_base_url = "https://api.instagram.com/v1/";
$this->api->authorize_url = "https://api.instagram.com/oauth/authorize/";
$this->api->token_url = "https://api.instagram.com/oauth/access_token";
}
/**
* load the user profile from the IDp api client
*/
public function getUserProfile()
{
$data = $this->api->api("users/self/");
if ($data->meta->code != 200) {
throw new \Exception("User profile request failed! {$this->providerId} returned an invalid response.", 6);
}
$this->user->profile->identifier = $data->data->id;
$this->user->profile->displayName = $data->data->full_name ? $data->data->full_name : $data->data->username;
$this->user->profile->description = $data->data->bio;
$this->user->profile->photoURL = $data->data->profile_picture;
$this->user->profile->webSiteURL = $data->data->website;
$this->user->profile->username = $data->data->username;
return $this->user->profile;
}
/**
*
*/
public function getUserContacts()
{
// refresh tokens if needed
$this->refreshToken();
//
$response = array();
$contacts = array();
$profile = ((isset($this->user->profile->identifier))?($this->user->profile):($this->getUserProfile()));
try {
$response = $this->api->api("users/{$this->user->profile->identifier}/follows");
} catch (\Exception $e) {
throw new \Exception("User contacts request failed! {$this->providerId} returned an error: $e");
}
//
if (isset($response) && $response->meta->code == 200) {
foreach ($response->data as $contact) {
try {
$contactInfo = $this->api->api("users/".$contact->id);
} catch (\Exception $e) {
throw new \Exception("Contact info request failed for user {$contact->username}! {$this->providerId} returned an error: $e");
}
//
$uc = new \Hybrid_User_Contact();
//
$uc->identifier = $contact->id;
$uc->profileURL = "https://instagram.com/{$contact->username}";
$uc->webSiteURL = #$contactInfo->data->website;
$uc->photoURL = #$contact->profile_picture;
$uc->displayName = #$contact->full_name;
$uc->description = #$contactInfo->data->bio;
//$uc->email = ;
//
$contacts[] = $uc;
}
}
return $contacts;
}
}
Changing the scope "basic" to "user_profile,user_media", it shows
different error
UPDATE
This is my Redirect URI
https://127.0.0.1/magento_241/sociallogin/social/callback/?hauth.done=Instagram
I'm not sure this could be the reason it's not working but green tick
is not showing next to the Instagram Basic display as it is showing for Facebook Login.
But my app is live here it shows live,
Somehow if I managed to log in (after entering credentials) no matter
what option do I choose in the below screenshot, it displays the error Oops, an error occurred. on this URL https://www.instagram.com/oauth/authorize/?client_id=MY_CLIENT_ID&redirect_uri=http%3A%2F%2F127.0.0.1%2Fmagento_241%2Fsociallogin%2Fsocial%2Fcallback%2F%3Fhauth.done&response_type=code&scope=basic
Let me know if anyone has a solution.
The API has changed. The Url for authorization now looks different:
https://api.instagram.com/oauth/authorize?client_id=XXXXXX&redirect_uri=XXXXXX&scope=user_profile,user_media&response_type=code
Just exchange it in your request and it will work just fine.
Scope "basic" is deprecated from what I've seen. I've solved this error in Laravel by setting scopes independently from package:
return Socialite::driver('instagram')
->setScopes(['user_profile'])
->redirect();
Maybe if you remove public $scope = "basic"; it could solve your issue
While your redirect_uri might be working properly, have you made sure to add that URI to your Instagram App settings list of Valid OAuth Redirect URIs? If not, you will encounter an invalid redirect uri message.
To add this URI, go to your Facebook App's dashboard, then click on the sidebar to Basic Display:
Then, scrolling down on the right side, you will see the space for adding Valid OAuth Redirect URIs.

API management URL is giving Missing subscription key Issue

I am new to API management. I have created a Basic WEB API & hosted to the API APP(App service). URL is working as expected & it's returning the data. i.e. http://xyz.azurewebsites.net/api/webapi
But when I am adding the API App in the API management, I am getting different URL with Extra suffix I am adding, But when I am trying to open in browser Link--> https://abc.azure-api.net/God am getting the below error
{ "statusCode": 401, "message": "Access denied due to missing subscription key. Make sure to include subscription key when making requests to an API." }
If its no issue with API APP then it shouldn't be with API management. Please guid me if something I am missing.
NB--> I have tried adding the Subscription Key in fiddler its different issue is coming. but to access a URL it doesn't require Subscription Key basically.
If you enable the option to Require subscription for the product settings, then you must pass the below header Ocp-Apim-Subscription-Key.
Even you provide subscription key, the key should belong to the product which the API includes.
If you don't want the subsciption option, disable it in the product settings.
If you enable the option to Require subscription for the product settings, then you must pass the below header Ocp-Apim-Subscription-Key. Even you provide subscription key, the key should belong to the product which the API includes. Add the your APIs in your products.
Select the Products menu/link from Azure portal.
Select the product from list.
Select the APIs from selected product options.
Click on Add button and select your API from list and click on Select.
You are good to use your API using Postman or your code.
You have to pass the subscription key in header key (Ocp-Apim-Subscription-Key).
You can find the subscription key (Primary/Secondary) in api developer portal on profile screen.
You have to pass your subscription key in request headers.
Add this to your C# code
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Headers.Add("Authorization", BearerToken);
request.Headers.Add("Ocp-Apim-Subscription-Key", config["OcpApimSubscriptionKey"]);
Add this to your app settings file
"OcpApimSubscriptionKey": "your key",
Sample code:
try
{
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("Authorization", BearerToken);
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", config["OcpApimSubscriptionKey"]);
HttpResponseMessage response = client.GetAsync(url).Result;
if (response.IsSuccessStatusCode)
{
return response.Content.ReadAsStringAsync().Result;
}
else
{
var ResponseResult = await response.Content.ReadAsStringAsync();
return ResponseResult;
}
}
}
catch (WebException ex)
{
WebResponse errorResponse = ex.Response;
using (Stream responseStream = errorResponse.GetResponseStream())
{
StreamReader reader = new StreamReader(responseStream, System.Text.Encoding.GetEncoding("utf-8"));
string errorText = reader.ReadToEnd();
}
throw;
}
catch (ArgumentNullException ex)
{
throw;
}
catch (InvalidOperationException ex)
{
throw;
}
catch (HttpRequestException ex)
{
throw;
}

C# CSOM Sharepoint Bearer request from azure active directory

I am using the following approach as the basis of this (https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-devquickstarts-webapi-dotnet).
I got all this example working after setting up azure. But now we need to port it to an actual existing mobile app and web api app. The mobile app can get the Bearer token, but when we pass it to the web api, we pass this in a CSOM request as follows, but we still get a 401 Unauthroised response.
public static ClientContext GetSharepointBearerClientContext(this JwtTokenDetails tokenDetails)
{
var context = new ClientContext(tokenDetails.SiteUrl);
//context.AuthenticationMode = ClientAuthenticationMode.Anonymous;
context.ExecutingWebRequest += new EventHandler<WebRequestEventArgs>((s, e) =>
{
e.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + tokenDetails.BearerToken;
});
return context;
}
Our web api doesn't use any of the tech as in the example above, as I presume that we should just be able to pass the token through the CSOM request in the header, but this is not working, what else could I look at?
I have assigned the Office 365 Sharepoint Online (Microsoft.Sharepoint) permission and set the following
I have also done the same for the app registration, which we don't really use! Still not sure how the app registration comes into it)...
So this was possible, it was just microsoft telling us to put in an incorrect value. All the documentation says put the APP ID URI in the Resource. But in our case it needed to be the sharepoint url.
So we have the tenant name which on azure id the domain name e.g. srmukdev.onmicrosoft.com
Tenant: srmukdev.onmicrosoft.com
Application Id: This is the guid for the app registered in azure active directory.
RedirectUri: This can be any url(URI), its not actually used as a url for a mobile app as far as I can see.
ResourceUrl: srmukdev.sharepoint.com
The code I am using to get a token is as follows for a WPF example. The aadInstance is https://login.microsoftonline.com/{0}
private static string authority = String.Format(CultureInfo.InvariantCulture, aadInstance, tenant);
public async void CheckForCachedToken(PromptBehavior propmptBehavior)
{
//
// As the application starts, try to get an access token without prompting the user. If one exists, populate the To Do list. If not, continue.
//
AuthenticationResult result = null;
try
{
result = await authContext.AcquireTokenAsync(resourceUrl, applicationId, redirectUri, new PlatformParameters(propmptBehavior));
TokenTextBox.Text = result.AccessToken;
// A valid token is in the cache - get the To Do list.
GetTokenButton.Content = "Clear Cache";
}
catch (AdalException ex)
{
if (ex.ErrorCode == "user_interaction_required")
{
// There are no tokens in the cache. Proceed without calling the To Do list service.
}
else
{
// An unexpected error occurred.
string message = ex.Message;
if (ex.InnerException != null)
{
message += "Inner Exception : " + ex.InnerException.Message;
}
MessageBox.Show(message);
}
return;
}
}

Azure App Services (Mobile Apps) AAD authentication token refresh

I am trying to use Azure Active Directory to perform login functions on my uwp app. This happens successfully however I cannot get it to refresh the token when it expires and always receive the error "Refresh failed with a 403 Forbidden error. The refresh token was revoked or expired." and so I have to bring up the login window again. I am using the version 2.1.0 and the following code to authenticate:
private async Task<bool> AuthenticateAsync(bool forceRelogon = false)
{
//string message;
bool success = false;
// Use the PasswordVault to securely store and access credentials.
PasswordVault vault = new PasswordVault();
PasswordCredential credential = null;
//Set the Auth provider
MobileServiceAuthenticationProvider provider = MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory;
MobileServiceUser user = null;
try
{
// Try to get an existing credential from the vault.
var credentials = vault.FindAllByResource(provider.ToString());
credential = credentials.FirstOrDefault();
}
catch (Exception ex)
{
// When there is no matching resource an error occurs, which we ignore.
Debug.WriteLine(ex);
}
if (credential != null && !forceRelogon)
{
// Create a user from the stored credentials.
user = new MobileServiceUser(credential.UserName);
credential.RetrievePassword();
user.MobileServiceAuthenticationToken = credential.Password;
// Set the user from the stored credentials.
App.MobileService.CurrentUser = user;
//message = string.Format($"Cached credentials for user - {user.UserId}");
// Consider adding a check to determine if the token is
// expired, as shown in this post: http://aka.ms/jww5vp.
if (RedemptionApp.ExtensionMethods.TokenExtension.IsTokenExpired(App.MobileService))
{
try
{
await App.MobileService.RefreshUserAsync();
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
success = true;
}
else
{
try
{
// Login with the identity provider.
user = await App.MobileService
.LoginAsync(provider);
// Create and store the user credentials.
if (credential != null)
vault.Remove(credential);
credential = new PasswordCredential(provider.ToString(),
user.UserId, user.MobileServiceAuthenticationToken);
vault.Add(credential);
success = true;
//message = string.Format($"You are now logged in - {user.UserId}");
}
catch (MobileServiceInvalidOperationException)
{
//message = "You must log in. Login Required";
}
}
//var dialog = new MessageDialog(message);
//dialog.Commands.Add(new UICommand("OK"));
//await dialog.ShowAsync();
return success;
}
Can anyone see something wrong with what I am doing, or need to do anything within the AAD service provider?
You might be able to get more accurate information by taking a look at the server-side application logs. Token refresh failure details will be logged there automatically. More details on application logs can be found here: https://azure.microsoft.com/en-us/documentation/articles/web-sites-enable-diagnostic-log/. I recommend setting the trace level to Informational or Verbose.
Also, if you haven't done this already, Azure AD requires a bit of extra configuration to enable refresh tokens. Specifically, you need to configure a "client secret" and enable the OpenID Connect hybrid flow. More details can be found in this blog post: https://cgillum.tech/2016/03/07/app-service-token-store/ (scroll down to the Refreshing Tokens section and see where it describes the process for AAD).
Besides what has been said about mobile app configuration, I can spot this.
You have:
// Login with the identity provider.
user = await App.MobileService.LoginAsync(provider);
It should be:
user = await App.MobileService.LoginAsync(MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory,
new Dictionary<string, string>() {{ "response_type", "code id_token" }});
Maybe this will help:
https://azure.microsoft.com/en-us/blog/mobile-apps-easy-authentication-refresh-token-support/

OpenID OWIN auth and lack of user permissions

I may be handling this totally incorrect, but I am using OpenID with MS Azure to authentication my users, then I check to make sure the user has a user account in the notifications of the OpenID middleware, if the user is not found, I am throwing a security exception. How do I return a You do not have access to this applicaiton type page. Am I just missing the hook?
Here is the example:
https://gist.github.com/phillipsj/3200ddda158eddac74ca
You can use try...catch inside the notifications, something along these lines:
SecurityTokenValidated = (context) =>
{
try
{
// retriever caller data from the incoming principal
var username = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.Name).Value.Split('#')[0];
var database = DependencyResolver.Current.GetService(typeof (IDatabase)) as IDatabase;
var employee = database.Query(new GetEmployeeByUsername(username));
if (employee == null)
{
throw new SecurityTokenValidationException();
}
// I add my custom claims here
context.AuthenticationTicket.Identity.AddClaims(claims);
return Task.FromResult(0);
}
catch (SecurityTokenValidationException ex)
{
context.HandleResponse(); // This will skip executing rest of the code in the middleware
context.Response.Redirect(....);
return Task.FromResult(0);
}
}

Resources