I am failing at retrieving my activities feed (/me/activities) from Soundcloud & thought someone might be able to point out what I'm doing incorrectly.
I can access the /connect endpoint, but only if I specify a scope value of non-expiring. Using a value of * returns the error invalid_scope with an error_description of:
The requested scope is invalid, unknown or malformed.
I can exchange the resulting code for a token at the /oauth2/token endpoint, but only when setting grant_type to client_credentials.
I've attempted to request /me/activities with both GET and POST, providing oauth_token (and trying with and without a limit argument) and am being met with a 403 response * the following response header error:
OAuth realm="SoundCloud", error="insufficient_scope"
Requesting a grant_type of authorization_code when requesting at /oauth2/token fixed the issue.
Related
I'm trying to use the Microsoft Bing Ads' Reporting API to gather ad performance data such as clicks, spend, etc. programmatically. Below, I describe the steps taken.
There are two issues -
1 - I have to request for user consent again and again as access token
is short lived and refreshed token also giving unauthenticated token
error.
2 - After following the steps I don't get the expected SOAP
Response. Instead I get below response.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:DeserializationFailed</faultcode>
<faultstring>The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter https://bingads.microsoft.com/Reporting/v13:ReportRequest. The InnerException message was 'Error in line 13 position 71. Element 'https://bingads.microsoft.com/Reporting/v13:ReportRequest' contains data of the ':AccountPerformanceReportRequest' data contract. The deserializer has no knowledge of any type that maps to this contract. Add the type corresponding to 'AccountPerformanceReportRequest' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.</faultstring>
</s:Fault>
</s:Body>
</s:Envelope>
I'm using Postman to test the service and my end goal is to use http to do the same in Mulesoft later. This is the URL I am using
https://reporting.api.bingads.microsoft.com/Api/Advertiser/Reporting/V13/ReportingService.svc
Authentication
I have followed their OAuth 2.0 Authentication Flow in that, I have:
Registered my Application (using the Developer Account)
Requested user consent (through the Ad account)
Generated the Access Token and Refresh Token Every time I hit the API.
**
I generate a new Access Token by requesting user consent again and again as refreshing
token is also not working.
**
Making the Request
The documentation describes a Reporting Service Operation which follows an asynchronous approach. First we need to use SubmitGenerateReport to make a request to the Reporting Service. This returns a ResponseRequestId which we can then use to repeatedly poll the service using PollGenerateReport till we get the requested report in response.
SubmitGenerateReport
SubmitGenerateReport has to be in SOAP XML Format as stated here. Following is the document I generated for my use case looking at the provided example in the documentation. Action I am passing as header attribute - SOAPAction:SubmitGenerateReport
<x:Envelope
xmlns:x="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:v="https://bingads.microsoft.com/Reporting/v13"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<x:Header>
<v:AuthenticationToken>****</v:AuthenticationToken>
<v:CustomerAccountId>****</v:CustomerAccountId>
<v:CustomerId>****</v:CustomerId>
<v:DeveloperToken>****</v:DeveloperToken>
</x:Header>
<x:Body>
<v:SubmitGenerateReportRequest>
<v:ReportRequest i:type="AccountPerformanceReportRequest">
<v:Format>Csv</v:Format>
<v:ReportName>AccountPerformanceReportRequest</v:ReportName>
<v:Aggregation>Summary</v:Aggregation>
</v:ReportRequest>
</v:SubmitGenerateReportRequest>
</x:Body>
</x:Envelope>
I even tried passing all the input variables, scope, time etc but getting some error again. I understand error clearly tells me where the error is but the report types I am using are given in Microsoft documentations.
Any help and suggestion would be really helpful.
1. I have to request for user consent again and again as access token is short lived and refreshed token also giving unauthenticated token error.
I would like to point you to these tutorial, as reference for my code below.
https://learn.microsoft.com/en-us/advertising/guides/get-started?view=bingads-13
https://learn.microsoft.com/en-us/advertising/guides/authentication-oauth-quick-start?view=bingads-13
In the first step, you fetch code, for this you need browser verification.
$clientId = '...'
Start-Process "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=$clientId&scope=openid%20profile%20https://ads.microsoft.com/msads.manage%20offline_access&response_type=code&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient&state=ClientStateGoesHere&prompt=login"
$code = 'https://login.microsoftonline.com/common/oauth2/nativeclient?code=<code>&state=ClientStateGoesHere'
$code = $code -match 'code=(.*)\&'
$code = $Matches[1]
Now, using this code, you get accessToken/refreshToken.
$response = Invoke-WebRequest https://login.microsoftonline.com/common/oauth2/v2.0/token -ContentType application/x-www-form-urlencoded -Method POST -Body "client_id=$clientId&scope=https://ads.microsoft.com/msads.manage%20offline_access&code=$code&grant_type=authorization_code&redirect_uri=https%3A%2F%2Flogin.microsoftonline.com%2Fcommon%2Foauth2%2Fnativeclient"
$oauthTokens = ($response.Content | ConvertFrom-Json)
Since, this access token $oauthTokens.access_token will expire after one hour, use the refresh token to get new access and refresh tokens. This process you need to do periodically, say on 1/2 hourly basis.
Process to refresh is the following. This does not require you to login.
$response = Invoke-WebRequest https://login.microsoftonline.com/common/oauth2/v2.0/token -ContentType application/x-www-form-urlencoded -Method POST -Body "client_id=$clientId&scope=https://ads.microsoft.com/msads.manage%20offline_access&code=$code&grant_type=refresh_token&refresh_token=$($oauthTokens.refresh_token)"
$oauthTokens = ($response.Content | ConvertFrom-Json)
PS, I'm unclear if we could refresh infinitely or whether it is bound to a day. I verified that an expired accessToken could be renewed via refreshToken via this method after 1.5 hours - no need of generating code again via relogin.
2. After following the steps I don't get the expected SOAP Response. Instead I get below response
Thank you for providing the detailed soap xmls. I tried the same on my test account and able to repro exact same error message.
Here's the udpated SOAP xml request I used to get it to work.
<s:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header xmlns="https://bingads.microsoft.com/Reporting/v13">
<AuthenticationToken i:nil="false">here goes token</AuthenticationToken>
<CustomerAccountId i:nil="false">176045209</CustomerAccountId>
<CustomerId i:nil="false">169549046</CustomerId>
<DeveloperToken i:nil="false">here goes dev Token</DeveloperToken>
</s:Header>
<s:Body>
<SubmitGenerateReportRequest xmlns="https://bingads.microsoft.com/Reporting/v13">
<ReportRequest i:nil="false" i:type="AccountPerformanceReportRequest">
<Format i:nil="false">Csv</Format>
<ReportName i:nil="false">reportName1</ReportName>
<!--These fields are applicable if the derived type attribute is set to AccountPerformanceReportRequest-->
<Aggregation>Summary</Aggregation>
<Columns i:nil="false">
<AccountPerformanceReportColumn>Impressions</AccountPerformanceReportColumn>
<AccountPerformanceReportColumn>Revenue</AccountPerformanceReportColumn>
<AccountPerformanceReportColumn>AccountName</AccountPerformanceReportColumn>
</Columns>
<Scope i:nil="false">
<AccountIds i:nil="false" xmlns:a1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a1:long>176045209</a1:long>
</AccountIds>
</Scope>
<Time i:nil="false">
<CustomDateRangeEnd i:nil="false">
<Day>22</Day>
<Month>07</Month>
<Year>2022</Year>
</CustomDateRangeEnd>
<CustomDateRangeStart i:nil="false">
<Day>01</Day>
<Month>07</Month>
<Year>2022</Year>
</CustomDateRangeStart>
</Time>
</ReportRequest>
</SubmitGenerateReportRequest>
</s:Body>
</s:Envelope>
Here's the postman result.
PS, I received error, when some fields were missing. I did not use xml namespaces.
Hope this helps.
Note - I am very much new to all this. Apologies if anything is unclear.
My overriding aim is to pull out MOT history data for a large batch of vehicles from the DVLA API. I understand that this can be done using Postman, which I am using (on a 64-bit Windows laptop if at all relevant).
The DVLA provide the following instructions
====================================================
Getting started
All API interfaces are implemented as restful APIs and accessed over https.
To access API you will need an API key that uniquely identifies the source of the request. DVSA will give you an API key if it approves your application.
You should keep your API key secure, as DVSA manages throttling and quotas at an API key level.
Each request must have the following mandatory fields in the header:
Accept: application/json+v6
x-api-key:
Content-type field confirms that the response type is in JSON format, and the x-api-key field serves your API key to identify the source of the request.
Technical resources
Access the API at https://beta.check-mot.service.gov.uk/
This root URL will change when the service moves from beta to live.
These 4 endpoints equate to the 4 methods of using the API:
/trade/vehicles/mot-tests?registration={registration}
‘Registration’ is the vehicle registration number.
===================================================
In order to test that this is possible, I am entering the following single request into the bar in Postman, selecting "POST" and hitting "SEND"
https://beta.check-mot.service.gov.uk/trade/vehicles/mot-tests?Content-type=application/json&x-api-key=ABCDEFGH®istration=MYREG
n.b. no inverted commas or other punctuation surrounds the actual values for ABCDEFH or MYREG
Expected result: Some sort of JSON with MOT history for this vehicle
Actual result: {"message": "Missing Authentication Token"}{"message": "Missing Authentication Token"}
I am unclear on:
- whether I should be using POST
what the +v6 after the application is necessary (other documentation leaves it out)
Why "Accept" and "Content-type" appear to be used interchangeably in the documentation
Whether the ordering of the parameters matters
Whether this can be equally tested by simply pasting the url into a browser
Thanks for any help
Reading through the Documentation found here:
https://dvsa.github.io/mot-history-api-documentation/
It mentions that those fields should be added as Headers:
Each request must have the following mandatory fields in
the header:
- Accept: application/json+v6
- x-api-key: <your api key>
There are example cURL requests on the site to help you with creating the request.
If you use Postman's Import feature within the app (found in the top right), you can add this cURL request in the Paste Raw Text tab.
curl -H "Accept: application/json+v6" -H "x-api-key: <your_api_key>" https://beta.check-mot.service.gov.uk/trade/vehicles/mot-tests\?registration=ZZ99ABC
This will give you an example request of what it should look like. From here, you will be able to add in your own API Token and send the request.
If you are using Postman, you can use the Authorization tab right under the request to give the required mandatory header fields. Select Header from Add to drop down. You can also add additional headers information using the next tab named Headers. (for example, the accept-headers).
Edit:
Authorization:
Headers Tab
Normally, you should be getting the authorization token when you register to the site in question(x-api-key here).You need to figure out the value of that token from the initial call's response headers. According to the document which Danny shared, you will be getting x-api-key from them once they approve your request.
Edit:
Alternatively, you can use import feature as Danny suggested in his answer. At the end of the day, you need to add the values as headers instead of query parameters.
For anyone using Python with the MOT history api and getting the same error message, try GET:
import requests
url = f'https://beta.check-mot.service.gov.uk/trade/vehicles/mot-tests?registration={plate_number}'
payload = {}
headers = {
'Accept': 'application/json+v6',
'x-api-key': 'your-api-key'}
response = requests.get(url, headers=headers, data=payload)
data = response.json()
model = data[0]['model'] # get the vehicle model for example
print(model)
Certain APIs in my project can only be accessed via OAuth 2.0 using an encoded format. I am able to manually submit a POST using POSTMAN as it has the x-www-form-urlencoded feature to send the request (image attached). As a workaround, I created a java function to convert my json body to an encoded URI and passed as a variable. However, I am getting a "http call failed for URL" when running it. I was wondering if Karate has its own library to convert json to Encoded URIs.
Scenario: Json to Encoded URI on POST body
* def JavaDemo = Java.type('com.ge.health.gam.service.servicerequest.testsuite.CustomJavaClass')
* def encodedURI = JavaDemo.jsonToURI()
* print encodedURI
Given url 'http://location.ver02.geicenter.com/uaa/oauth/token'
And request encodedURI
When method post
Then status 200
com.intuit.karate.exception.KarateException: http call failed after 263 milliseconds for URL: http://location.ver02.geicenter.com/uaa/oauth/token
As suggested by Peter Thomas, I found the below to be able to submit requests via Oath 2.0. In my case, I also had to install a required certificate in order to receive a valid response. you also have to take that into consideration.
Given path 'uaa', 'oauth', 'token'
And form field key = 'value'
And form field key = 'value'
And form field key = 'value'
And form field key = 'value'
When method post
Then status 200
Yes. Please refer to the documentation for form field. There is also an OAuth 2 example in the demos, look for it.
Also see: https://stackoverflow.com/a/58643689/143475
Our client has given us their end point and when we are try to hit their API we are getting below Error
'{"error":"invalid_scope","error_description":"Scope must be
specified"}'
It seems that your API is not getting hit properly.Use Postman to call the API and enter the proper parameter.If your API is correct and you are passing the correct parameter it will work.
I've generated Access Tokens in the Settings/..../ Keys and Access Tokens page and now have a
Consumer Key
Consumer Secret Key
Owner ID (even though this was probably already generated)
Access Token
Access Token Secret
and am using a rest client to test being able to pull the latest 3 statuses using this api end point
https://api.twitter.com/1.1/statuses/user_timeline.json?user_id=userIdHere&count=3
as well as the following headers
Accept: /
Connection: close
User-Agent: OAuth gem v0.4.4
Content-Type: application/x-www-form-urlencoded
Content-Length: 76
Host: api.twitter.com
Authorization: OAuth
oauth_consumer_key=
oauth_signature=
oauth_signature_method=
oauth_timestamp=
oauth_token=
oauth_version=
obviously the 'userIdHere' in the end point address (above) is substituted with my username (i know i can also use my user_id, but that's beside the point) as well as the 'Authorization' values being substituted for real values. That's where my question lies...
What is the mapping for each of the 'oauth...' authorization parameters to their associated Twitter generated and provided Token or key(s) (which were mention near the top of the post)?
I keep getting a '400 Bad Request' response and feel that it is the authorization that is failing in that the permutations of key placements is incorrect. I do not know which value goes to which 'oauth...' value
finally, the structure of the 'Authorization' parameter header is as follows (as per instruction here from the Twitter EXAMPLE) as one line string value
OAuth oauth_consumer_key="xvz1evFS4wEEPTGEFPHBog", oauth_nonce="kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg", oauth_signature="tnnArxj06cWHq44gCs1OSKk%2FjLY%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1318622958", oauth_token="370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb", oauth_version="1.0"
)
I am just trying to use a GET to get the last 3 statuses and have not been able to. Also, i plan to switch the values to Environmental Variables, but that doesn't matter yet..
UPDATE
using Postman now, and it's better at mapping, but now am getting
{
"errors": [
{
"code": 32,
"message": "Could not authenticate you."
}
]
}
For the Postman part make sure that you leave Timestamp and nonce empty and hit "update request" before you hit send. That will generate timestamp and nonce - otherwise you will get authorization failures every time. I just tried it with my twitter API credentials and it works.
For Oauth gem code, I find it strange that you have a Content-Type and a Content-Length header for a GET request. Looks like the 400 Bad request could be because you are attempting to do a POST to an endpoint that only supports GET. Indeed when I try to do a POST to that endpoint it tells me.
{
"errors": [
{
"code": 86,
"message": "This method requires a GET or HEAD."
}
]
}
So the 400 is actually good news - it means that authorization works, you are just calling the API in the wrong way.