Client credential grant type is not properly sent with Apache Oltu client library? - apache

I tried to implement an OAuth client using OAuthClientRequest in Apache Oltu. And it seems to be that it is sending client credentials in the message body not in the Basic Auth headers according to the spec. I am not sure, I may have missed some thing in the code.
Code
OAuthClientRequest.tokenLocation("http://localhost:8081/token")
.setGrantType(GrantType.CLIENT_CREDENTIALS)
.setClientId(clientKey)
.setClientSecret(clientSecret)
.buildBodyMessage();
Request
POST /token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Java/1.6.0_29
Host: 127.0.0.1:8081
Accept: text/html, image/gif, image/jpeg, *; q=.2, /; q=.2
Connection: keep-alive
Content-Length: 127
client_secret=f921854d-f70b-4180-9fdd-3a55032103cc&grant_type=client_credentials&client_id=3f3b4092-7576-4b26-8135-980db7864c2

You might want to change buildBodyMessage() with buildQueryMessage()

The OAuth2 Bearer Token specification defines three methods of sending bearer access tokens:
Authorization Request Header Field
Form-Encoded Body Parameter
URI Query Parameter
The method buildBodyMessage() will create a request with a Form-Encoded Body Parameter. You need to use buildHeaderMessage() instead, which is also the recommended method by the specification.

Recently, I've trying to find a OAuth2 java library to get "client_credential" type of accesstoken. And below is what I have for Apache Oltu, and it seems that it is working.
#Test
public void getAccessTokenViaApacheOltuOAuthClient() {
try{
OAuthClient client = new OAuthClient(new URLConnectionClient());
OAuthClientRequest request =
OAuthClientRequest.tokenLocation(TOKEN_REQUEST_URL)
.setGrantType(GrantType.CLIENT_CREDENTIALS)
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
.setScope(StringUtils.join(TEST_SCOPES, " ")) //if you have scope
.buildBodyMessage();
String token =
client.accessToken(request, "POST", OAuthJSONAccessTokenResponse.class)
.getAccessToken();
System.out.println(token);
assertTrue( token != null);
} catch (Exception e) {
e.printStackTrace();
}
}

Related

xero api fails with unauthorized (401 or 403) after calling auth, refresh and gettenants when calling getinvoices

I'm a rank noob at this, so excuse my ignorance. I've got an MVC web application to login, get the access and refresh tokens, and tenant list OK. I can even get it to refresh the refresh token. No problems.
When I try to run the GetInvoices endpoint either directly or via the sdk, I get 403 (skd) or 401 from the direct api call.
From the latest run with direct call I get this response
{StatusCode: 401, ReasonPhrase: 'Unauthorized', Version: 1.1, Content:
System.Net.Http.HttpConnectionResponseContent, Headers:
{
Server: nginx
Strict-Transport-Security: max-age=31536000
WWW-Authenticate: OAuth Realm="api.xero.com"
Cache-Control: no-store, no-cache, max-age=0
Pragma: no-cache
Date: Wed, 21 Jul 2021 11:19:56 GMT
Connection: close
X-Client-TLS-ver: tls1.2
Content-Type: text/html; charset=utf-8
Content-Length: 95
Expires: Wed, 21 Jul 2021 11:19:56 GMT
}, Trailing Headers:
{
}}
I know that the access token and tenant id used in the GetInvoices step are correct because I checked them against the values pulled in from the auth steps character by character.
The app is being run in Visual Studio 2019, using the self-signed development SSL certificate.
Why is it rejecting the request?
my controllers have the following
private static readonly string Scopes = "openid offline_access profile email accounting.transactions accounting.contacts accounting.attachments";
private static readonly string Scopes = "openid offline_access profile email accounting.transactions accounting.contacts accounting.attachments";
string[] tenant = (string[])TempData.Peek("tenant");
var client = new HttpClient();
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("summaryOnly", "true"),
});
client.DefaultRequestHeaders.Add("Authorization", (string)TempData.Peek("accessToken"));
client.DefaultRequestHeaders.Add("Xero-Tenant-Id", tenant[0]);
client.DefaultRequestHeaders.Add("Accept", "application/json");
var response = await client.PostAsync("https://api.xero.com/api.xro/2.0/Invoices", formContent);
The SDK should handle this for you in the helper methods for the client and OAuth flow but i've included what looks like is missing from just a raw API call below.
Core API call - looks like you need to prefix the token with the Bearer string.
Authorization: "Bearer " + access_token
If you are wanting to use the SDK note that there is a sub Nuget package for OAuth helpers that will help you obtain an access token which you need to pass to core api calls.
https://github.com/XeroAPI/Xero-NetStandard/tree/master/Xero.NetStandard.OAuth2Client
(DOH!) The Tenant returns an Id and a TenantId. I was using the Id.
Thanks to SerKnight and droopsnoot for helping.
I've added code from the OAuth2. The help does not mention to get and cast the return type of RequestAcessTokenAsync.
XeroOAuth2Token authToken = (XeroOAuth2Token)await client.RequestAccessTokenAsync(authorisationCode);
also to check the state on return, you must set in xconfig. mine reads
XeroConfiguration xconfig = new()
{
ClientId = Global.XeroClientID,
ClientSecret = Global.XeroClientSecret,
CallbackUri = new Uri(Global.RedirectURI),
Scope = Global.XeroScopes,
State = Global.XeroState
};
var client = new XeroClient(xconfig);
return Redirect(client.BuildLoginUri());

Why does this REST request work from every client except Talend API tester

This is an example of a REST POST request that works everywhere except Talend API tester. It give a 500 error.
Here is how I set the request up in my applications.
URLConnection connection = new URL("https://" + authHost + "/connect/token").openConnection();
logger.info("Connection oppened");
// message contains the form data: key=value&key=value&key=value
String message = "password=" + password + "&grant_type=password&username=" + username +
"&client_id=foolid&scope=mouthwash";
logger.info(message);
// Setting header fields.
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Accept", "application/json");
connection.getOutputStream().write(message.getBytes("UTF-8"));
Here is a working example in Postman
POST /connect/token HTTP/1.1
Host: identityserver.uat.example.com
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Cookie: ARRAffinity=6a37d2ecf3441e27913cb832c4b767c68cad0e45c8806b3c5344d1b52d57f67a; ARRAffinitySameSite=6a37d2ecf3441e27913cb832c4b767c68cad0e45c8806b3c5344d1b52d57f67a
Content-Length: 137
password=secret&grant_type=password&username=fool&client_id=foolid&scope=mouthwash
And here is what Talend say it sends, which gets the 500 error -- which I understand comes from the server.
POST /connect/token HTTP/1.1
Accept: application/json
Content-Length: 137
Content-Type: application/x-www-form-urlencoded
Host: identityserver.uat.example.com
password=secret&grant_type=password&username=fool&client_id=foolid&scope=mouthwash
What's happening here?

Get shopify analytics token programmatically

How do you get the token needed to make a request to the Shopify analytics API?
For example:
POST https://analytics.shopify.com/queries?beta=true
REQUEST BODY:
token: HOW_DO_I_GET_THIS?
q[]: SHOW+total_visitors+AS+%22total_visitors...
source: shopify-reports
I've tried using OAuth, but it seems to be a different token entirely.
You have to request Shopify Core GraphQL to get analyticsToken.
POST /admin/internal/web/graphql/core HTTP/1.1
Host: [[STORE_NAME]].myshopify.com
Accept: application/json
Accept-Language: en-CA,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
content-type: application/json
X-CSRF-Token: [[CSRF_TOKEN]]
Origin: https://[[STORE_NAME]].myshopify.com
Connection: close
Cookie: [[COOKIE]]
{ "query": "{ shop { analyticsToken } }" }
Since the request requires CSRF Token & Cookie, it's not programmatic at all.
For additional information please check the Examples for Testing in the Shopify Admin page.

WebAPI 2 with OWIN middleware and token-based authentication: OPTIONS request returns "unsupported_grant_type" error

WEbAPI provides end-point for authentication request: http:\...\token
Authentication request should be sent using Method "POST" and Body like
"grant_type=password&username=name&password=mypassword"
This WebAPI is used by Front-End which is written using AngularJS.
Sometimes before sending "POST" request with valid Body, a "OPTIONS" request is sent without Body.
As result the following error is returned by WebAPI:
Status: 400
{"error":"unsupported_grant_type"}
Is there any solution which can be implemented on Server-side? (in WebAPI)
HTTP Request Method: OPTIONS
Request Header:
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,de;q=0.6,ru;q=0.4,uk;q=0.2
Access-Control-Request-Headers:accept, authorization, content-type
Access-Control-Request-Method:POST
Cache-Control:no-cache
Host:...
Origin:...
Pragma:no-cache
Proxy-Connection:keep-alive
Referer:...
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36
Response Header:
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 34
Content-Type: application/json;charset=UTF-8
Expires: -1
Server: Microsoft-IIS/7.5
Access-Control-Allow-Origin: *
X-Powered-By: ASP.NET
Date: Thu, 11 Sep 2014 18:05:09 GMT
I just ran into the same issue..I'm using ember and ember-simple-auth. Any preflight requests OPTIONS to the /token endpoint were resulting in a 400 HTTP response and the body had the well known: {error: "unsuported_grant_type"}.
SOLUTION:
I inherit from: OAuthAuthorizationServerProvider and override the MatchEndpoint function:
public override Task MatchEndpoint(OAuthMatchEndpointContext context)
{
if (context.OwinContext.Request.Method == "OPTIONS" && context.IsTokenEndpoint)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Methods", new[] {"POST"});
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "accept", "authorization", "content-type" });
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
context.OwinContext.Response.StatusCode = 200;
context.RequestCompleted();
return Task.FromResult<object>(null);
}
return base.MatchEndpoint(context); }
That seems to take care of it. Hope it helps.
I got the same error when I forgot to add Content-Type: application/x-www-form-urlencoded to the request header.
I was attempting to test my api with Fiddler and wasn't providing the data in the correct format in the Request Body section. Be sure it's added as a key value list separated by '&'.
grant_type=password&username=testUsername&password=testPassword
In this case OPTIONS is a CORS preflight request. It is sent in order to determine whether the actual request (POST) is safe to send. Cross-site requests are preflighted if uses methods other than GET, HEAD or POST or sets custom headers.
In order to avoid a 400 HTTP response, in your Startup class you should enable CORS for the OWIN middleware using UseCors extension method and define your custom System.Web.Cors.CorsPolicy.
using Microsoft.Owin.Cors;
using Microsoft.Owin.Security.OAuth;
using Owin;
namespace AuthorizationServer
{
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions()
{
});
}
}
}

Metro client hangs when calling WCF webserver with wsHttpBinding

I have generated a webservice client with a local wsdl using Metro 1.2 this way:
./wsimport.sh -extension -verbose -wsdllocation service.wsdl -s src -d target service.wsdl -Xendorsed
The wsdl uses SOAP 1.2 and wsHttpBinding. It's supposed to connect to a WCF server that's using NTLM as authentication method.
I have created an Authenticator to handle the NTLM authentication:
public class NtlmAuthenticator extends Authenticator
{
private String username = "";
private String password = "";
public NtlmAuthenticator(String username, String password) {
this.username = username;
this.password = password;
}
#Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password.toCharArray());
}
}
Which I set before each webservice method is called:
#WebEndpoint(name = "WSHttpBinding_ICustomerService")
public ICustomerService getWSHttpBindingICustomerService() {
ICustomerService service =
super.getPort(new QName("http://xmlns.example.com/services/Customer",
"WSHttpBinding_ICustomerService"), ICustomerService.class);
NtlmAuthenticator auth = new NtlmAuthenticator(username, password);
Authenticator.setDefault(auth);
return service;
}
If I use the wrong username/password, I get a 401 Unauthorized back, which is well and all, but when I use the correct username/password, the call hangs and I never get a response!
The request looks like this (captured it with netcat, so host is different, and no https):
POST / HTTP/1.1
Content-type: application/soap+xml;charset="utf-8";action="http://xmlns.example.com/services/ICustomerService/GetCustomer"
Password: [password]
Authorization: Basic [auth]
Username: [username]
Accept: application/soap+xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
User-Agent: JAX-WS RI 2.1.7-b01-
Cache-Control: no-cache
Pragma: no-cache
Host: localhost:5500
Connection: keep-alive
Content-Length: 603
[xml follows]
I have also tried with wget 1.12 (heard that 1.11 had problem with NTLM), but it too never yields a response, just waits.
[...]
---request end---
[writing POST file customerRequest.xml ... done]
HTTP request sent, awaiting response...
I've seen that others have gotten this behaviour before, but I have not been able to find out why. Can anyone shed some light on this? JDK 1.6 on linux.
I found that I missed a line in my generated client code that enabled Addressing and pass it to the getPort super method:
WebServiceFeature wsAddressing = new AddressingFeature(true);
ICustomerService service =
super.getPort(new QName("http://xmlns.example.com/services/Customer",
"WSHttpBinding_ICustomerService"), ICustomerService.class,
wsAddressing);
Why metro didn't generate this is beyond me. The method looked like this in the end:
#WebEndpoint(name = "WSHttpBinding_ICustomerService")
public ICustomerService getWSHttpBindingICustomerService() {
WebServiceFeature wsAddressing = new AddressingFeature(true);
ICustomerService service =
super.getPort(new QName("http://xmlns.example.com/services/Customer",
"WSHttpBinding_ICustomerService"), ICustomerService.class,
wsAddressing);
NtlmAuthenticator auth = new NtlmAuthenticator(username, password);
Authenticator.setDefault(auth);
return service;
}
This in turn added a SOAP header to the message:
<S:Header>
<To xmlns="http://www.w3.org/2005/08/addressing">https://services.example.com/CustomerService.svc</To>
<Action xmlns="http://www.w3.org/2005/08/addressing">http://xmlns.example.com/services/ICustomerService/GetCustomer</Action>
<ReplyTo xmlns="http://www.w3.org/2005/08/addressing">
<Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
</ReplyTo>
<MessageID xmlns="http://www.w3.org/2005/08/addressing">uuid:d33c2888-abfa-474d-8729-95d2bcd17a96</MessageID>
</S:Header>