I'm building a client for an api that uses http digest access authentication for authentication. I have studied the rfc to know the setup the required response headers and this works well on my emulator. Problem however is when I test on my phone (nokia E5), I found out that getting the www-authenticate header from the returned headers doesnt get the full value
[code]
// c = (HttpConnection) Connector.open(url) and other declarations
String digest = c.getHeaderField("WWW-Authenticate");
System.out.println(digest); // gives only: Digest
//no realm, qop and others
[/code]
I'm I doing something wrong or it is from the phone? What are my other options?
I have faced this problem in some nokias, and yes, it is a bogus HttpConnection implementation ... I suggest you to try creating a new header from the server side with a base64 encoded WWW-Authenticate-encoded header and using it instead, or you can do it the hard way and implement the whole HttpConnection from scratch ...
Related
I'm trying to read in a JSON reply from the Google Sheets API in a Java ME MIDP application. I've tried the following with other addresses and it receives their content fine but the actual API I want to use is Sheets and it always returns an "Certificate Failed Verification" exception.
HttpConnection c = null;
InputStream is = null;
StringBuffer str = new StringBuffer();
try
{
c = (HttpsConnection)Connector.open(urlstring);
c.setRequestMethod(HttpConnection.GET);
c.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
c.setRequestProperty("User-Agent","Profile/MIDP-2.1 Configuration/CLDC-1.1");
is = c.openInputStream();
int len = (int)c.getLength();
int ch;
while ( (ch = is.read() ) != -1)
{
str.append((char)ch);
}
}
catch( Exception e ){ alert( ""+e ); }
return str.toString();
Connector.open() implicitly returns a HttpsConnection if the URL starts with Https so it should still work.
An example of a HTTPS request
https://jsonplaceholder.typicode.com/posts/1
Which won't work but the above also allows for HTTP connections
http://jsonplaceholder.typicode.com/posts/1
Which will work.
Google Sheets however requires HTTPS and thus is not obtainable via the above code. How can I make a GET request over HTTPS to the sheets API? Thank you.
I had a similar problem when implementing an online highscore system for one of our games. It would fetch highscores fine on some phones but didn't work on other phones. The explanation:
Some phones have their own built-in "MIME-type checker". When you call (HttpConnection)Connector.open(urlstring) the phone expects a text/html response. When it instead gets a application/json (or other) response, the phone gives its own "Not found" error.
Not sure if your problem is related, but worth a try? See if you can add a mime-type "application/json" in the request header of the HttpConnection.
From what I've gathered it seems that when connecting over HTTPS the phone uses an older version of SSL or TLS which has since been deprecated causing some API's to not respond.
I found that if you make an API request over HTTPs with the Opera Mini web browser it works. Giving you the desired response but on closer inspection it seems Opera gets the response for you and gives it back via a different URL. In attempt to furnish these older devices that cannot use a newer version of SSL/TLS to make the secure connection themselves.
The DocuSign documentation goes through an easy to follow authorization flow for code grant. I'm able to get the "code" from the initial GET request to /oath/auth but getting the tokens gives me an error of "invalid_grant" when I try in postman. I've followed the steps and have a request that looks like this using account-d.docusign.com for host:
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic MjMwNTQ2YTctOWM1NS00MGFkLThmYmYtYWYyMDVkNTQ5NGFkOjMwODc1NTVlLTBhMWMtNGFhOC1iMzI2LTY4MmM3YmYyNzZlOQ==
grant_type=authorization_code&code=ey2dj3nd.AAAA39djasd3.dkn4449d21d
Two other members of my team have also tried with their developer accounts and all are getting invalid_grant errors. Is this no longer supported or are there common errors associated with this error that we might be able to investigate?
Re-check all of your values.
I was also getting the same invalid_grant response and could not figure out why at first. It turns out that I had a typo in the Content-Type header. I was using application/x-www-form-urlencode instead of application/x-www-form-urlencoded.
You may not be, but if you are submitting the exact Authorization Header as you've posted it here in your question (MjMwNTQ2YTctOWM1NS00MGFkLThmYmYtYWYyMDVkNTQ5NGFkOjMwODc1NTVlLTBhMWMtNGFhOC1iMzI2LTY4MmM3YmYyNzZlOQ==) it will fail with that message.
That is the base64 value for the sample integration key and sample secret key provided in their documentation. If you decode that string with an online base64decoder it will result in 230546a7-9c55-40ad-8fbf-af205d5494ad:3087555e-0a1c-4aa8-b326-682c7bf276e9. This is the same sample integration key and secret in the documentation.
Check the Authorization header you are submitting by encoding your integration key and secret (integrationKey:secret) using this online base64encoder. This will make sure the issue isn't with your base64 encoding of your integration key and secret. Once you have that value make sure your Authorization uses the word Basic before the value you got from this website. (Basic base64stringFromOnlineEncoder)
Check that the code your are submitting in the body of the post is not the sample code from their documentation. ey2dj3nd.AAAA39djasd3.dkn4449d21d is the sample code from their documentation. You may just be using that in your question as a placeholder but if you are submitting any of those values it will return invalid_grant. Make sure that the body of your post does not have any leading or trailing spaces.
Have the correct Content-Type set application/x-www-form-urlencoded
Have the correct Authorization header set Basic base64EncodedIntegrationKey:Secret
Have the correct body using the valid code received from the GET request to /oauth/auth with no leading or trailing spaces, making sure you're not using the values from your question.
If you are still having trouble and you are not doing a user application but are doing a service integration you can use Legacy Authentication to get your oAuth2 token.
Alternative Method using Legacy Authentication for Service Integrations
This method does not use a grant code. You pass in the integration key, username and password into the X-DocuSign-Authentication header in JSON format.
Demo Server: demo.docusign.net
Production Server: www.docusign.net API
Version: v2
POST https://{server}/restapi/{apiVersion}/oauth2/token
Content-Type: application/x-www-form-urlencoded
X-DocuSign-Authentication: {"IntegratorKey":"your_integrator_key","Password":"docusign_account_password","Username":"docusign_account_username"}
grant_type=password&client_id=your_integrator_key&username=docusign_account_username&password=docusign_account_password&scope=api
If you are building a user application that requires the user enter their docusign credentials to generate the token, this alternative will not work for you.
For anyone who is facing this error, I'd like to point out this note in the documentation:
Note: The obtained authorization code is only viable for 2 minutes. If more then two minutes pass between obtaining the authorization code and attempting to exchange it for an access token, the operation will fail.
I was struggling with the same error until I spotted the note and sped up my typing to meet the 2 minutes.
Hope it helps someone else.
In my case the problem was related to having set a wrong value for Content-Type header, namely "application/x-www-form-URIencoded" instead of the correct "application/x-www-form-urlencoded". Note though that in my case the problem was not a "typo" but an excessive trust in DocuSign documentation.
Indeed the wrong Content-Type is, at the time of writing, suggested directly into the documentation page where they describe the Authorization Code Grant workflow, see the image below for the relevant part.
Hopefully they will fix the documentation soon but for the time being be careful not to blindly copy & paste the code from their examples without thinking, as I initially did.
anyone have an idea what is wrong here I am getting a BadRequest with the following
{"error":"invalid_grant","error_description":"unauthorized_client"}
var client = new RestClient(ESIGNURL);
var request = new RestRequest("/oauth/token");
request.Method = Method.POST;
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", "Basic " + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(integrationkey+ ":" + secret)));
string body = "grant_type=authorization_code&code=" + code;
request.Parameters.Clear();
request.AddParameter("application/x-www-form-urlencoded", body, ParameterType.RequestBody);
var response = client.Execute(request);
I was getting this error as well. What I realized is I was appending the state at the end of the code before passing it to the oauth token endpoint.
This snippet is from Docusign explaining what are some other reasons for getting that error.
Invalid-error explanation
I just spent a day doing this (in NodeJS). I'll add a couple of things to the answers from before. First, I had to put:
"Content-Type": "application/x-www-form-urlencoded"
in the header. Otherwise it gave me the message:
{
"error": "invalid_grant",
"error_description": "unsupported_grant_type"
}
Second, the base64 encoding:
I used this in NodeJS and it worked
const integration_key = process.env.INTEGRATION_KEY;
const secret_key = process.env.SECRET_KEY;
const authinfo =
integration_key.toString("utf8") + ":" + secret_key.toString("utf8");
const buff2 = Buffer(authinfo, "utf8").toString("base64");
If you use "base64url" it dosen't work because it strips the == off of the end of the string. The = symbol is used as padding and apparently it's needed. You see a similar difference on this site https://www.base64encode.org/ when you toggle the url safe encoding option. If you don't have the padding on the end of your base64 encoded string (or if it's generally incorrect) you get this message:
{
"error": "invalid_grant",
"error_description": "unauthorized_client"
}
Finally, if you're using Postman (I'm using DocuSign's Postman Collection) remember to reset and save the codeFromUrl variable after you update it. Otherwise it doesn't update and you get the message:
{
"error": "invalid_grant",
"error_description": "expired_client_token"
}
This means the old URL code has expired and your new one didn't save.
I'm generating a token on our auth server (Node.js) in node-jsonwebtoken that will be passed to an API (PHP Laravel) and verified by tymondesigns/jwt-auth.
A token generated by tymondesigns/jwt-auth will be verified successfully by
its own verify function, node-jsonwebtoken and jwt.io.
A token generated by node-jsonwebtoken will be verified successfully by its own verify function, jwt.io, but not tymondesigns/jwt-auth.
On the Laravel server, i get the following error when I try to verify a token generated by node-jsonwebtoken:
TokenInvalidException in NamshiAdapter.php line 71:
Token Signature could not be verified.
The payloads look identical when I look at them over at jwt.io. I have even tried to generate the exact same token on the Node server by passing the same iat,sub,iss,exp,nbf and jti as generated by a working token, but tymondesigns/jwt-auth still won't accept it.
Is there anything else that could be causing this, but isn't visible in the decoded information? I'm also not 100% sure how jti works. Maybe there is something preventing this from working about that?
node-jsonwebtoken (7.1.9), tymon/jwt-auth (0.5.9), namshi/jose (5.0.2)
The last version of the namshi/jose library is 7.0.
There is also a known bugs for all ESxxx algorithms.
If you cannot verify signatures using that library, you could try with another one.
I developed a library that supports all features described in the RFCs related to the JWT, including encryption support.
The reason is, as mentioned by Spomky aswell, a bug in namshi/jose related to the iss claim. It is resolved in 7.0 which is used by tymon/jwt-auth 1.0.0-alpha.2. However, since there currently isn't a documented way to install 1.0.0-alpha.2, we probably have to wait for a stable release.
Until then, since the problem and the bug is related to the iss claim, removing the iss requirement from required_claims and generating the tokens without it solves the problem temporarily.
In my case I had a url inside the payload. PHP escapes slashes by default when encoding to JSON, while Node.js doesn't. When the verification JWT gets generated in PHP (with those extra backslashes) of course the final hashes won't match since the payload is just different. Solution is to use the JSON_UNESCAPED_SLASHES flag when converting to JSON inside your JWT library, I was using https://github.com/namshi/jose so I created a simple class like this one:
use Namshi\JOSE\SimpleJWS;
class SimpleJWSWithEncodeOptions extends SimpleJWS
{
protected static $encodeOptions = 0;
public static function setEncodeOptions($options)
{
self::$encodeOptions = $options;
}
/**
* Generates the signed input for the current JWT.
*
* #return string
*/
public function generateSigninInput()
{
$base64payload = $this->encoder->encode(json_encode($this->getPayload(), self::$encodeOptions));
$base64header = $this->encoder->encode(json_encode($this->getHeader(), self::$encodeOptions));
return sprintf("%s.%s", $base64header, $base64payload);
}
}
Then it could be used like:
SimpleJWSWithEncodeOptions::setEncodeOptions(JSON_UNESCAPED_SLASHES);
$jws = SimpleJWSWithEncodeOptions::load($token);
$jws->verify($key);
$data = $jws->getPayload();
This problem was very specific to my payload content but it could help someone
I am creating an ASP.NET MVC5 action method that implements a password reset endpoint and accepts a click-through from an email message containing a token. My implementation uses OWIN middleware and closely resembles the ASP.NET Identity 2.1 samples application.
As per the samples application, the token is generated by UserManager and embedded into a URL that is sent to the user by email:
var token = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
var encoded = HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes(token));
var uri = new Uri(Url.Link("ResetPasswordRoute", new { id = user.Id, token = encoded }));
The link in the email message targets an MVC endpoint that accepts the token parameter as one of its route segments:
[Route("reset-password/{id}/{token}"]
public async Task<ActionResult> PasswordResetAsync(int id, string token)
{
token = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(token));
// Implementation here
}
However, requests to this endpoint (using a URL generated in the above manner) fail with Bad Request - Invalid URL.
It appears that this failure occurs because the URL is too long. Specifically, if I truncate the token segment, it connects correctly to the MVC endpoint (although, of course, the token parameter is no longer valid). Specifically, the following truncated URL works ...
http://localhost:53717/account/reset-password/5/QVFBQUFOQ01uZDhCRmRFUmpIb0F3RS9DbCtzQkFBQUFzcko5MEJnYWlrR1RydnVoY2ZwNEpnQUFBQUFDQUFBQUFBQVFaZ0FBQUFFQUFDQUFBQUNVeGZZMzd4OTQ3cE03WWxCakIwRTl4NkVSem1Za2ZUc1JxR2pwYnJSbmJ3QUFBQUFPZ0FBQUFBSUFBQ0FBQUFEcEpnVXFXS0dyM2ZPL2dQcWR1K2x6SkgxN25UVjdMYlE2UCtVRG4rcXBjU0FBQUFE
... but it will fail if one additional character is added ...
http://localhost:53717/account/reset-password/5/QVFBQUFOQ01uZDhCRmRFUmpIb0F3RS9DbCtzQkFBQUFzcko5MEJnYWlrR1RydnVoY2ZwNEpnQUFBQUFDQUFBQUFBQVFaZ0FBQUFFQUFDQUFBQUNVeGZZMzd4OTQ3cE03WWxCakIwRTl4NkVSem1Za2ZUc1JxR2pwYnJSbmJ3QUFBQUFPZ0FBQUFBSUFBQ0FBQUFEcEpnVXFXS0dyM2ZPL2dQcWR1K2x6SkgxN25UVjdMYlE2UCtVRG4rcXBjU0FBQUFEf
I believe that the default IIS configuration setting for maxUrlLength should be compatible with what I am trying to do, but I have also tried explicitly setting it to a larger value, which did not solve the problem.
However, using Fiddler to examine the server response, I can see that the working URL generates a server response with the following header ...
Server: Microsoft-IIS/8.0
... whereas the longer URL is rejected with a response containing the following header ...
Server: Microsoft-HTTPAPI/2.0
This seems to imply that the URL is not being being rejected by IIS, but by a middleware component.
So, I am wondering what that component might be and how I might work around its effect.
Any suggestions please?
Many thanks,
Tim
Note: Although my implementation above Base64 encodes the token before using it in the URL, I have also experimented with the simpler approach used in the sample code, which relies on the URL encoding provided by UrlHelper.RouteUrl. Both techniques suffer from the same issue.
You should not be passing such long values in the application path of the URL as they are limited in length to something like 255 characters.
A slightly better alternative is to use a query string parameter instead:
http://localhost:53717/account/reset-password/5?token=QVFBQUFOQ01uZDhCRmRFUmpIb0F3RS9DbCtzQkFBQUFzcko5MEJnYWlrR1RydnVoY2ZwNEpnQUFBQUFDQUFBQUFBQVFaZ0FBQUFFQUFDQUFBQUNVeGZZMzd4OTQ3cE03WWxCakIwRTl4NkVSem1Za2ZUc1JxR2pwYnJSbmJ3QUFBQUFPZ0FBQUFBSUFBQ0FBQUFEcEpnVXFXS0dyM2ZPL2dQcWR1K2x6SkgxN25UVjdMYlE2UCtVRG4rcXBjU0FBQUFEf
That should be safe for at least 2000 characters (full URL) depending on the browser and IIS settings.
A more secure and scalable approach is to pass a token inside an HTTP header.
I am trying to make a simple REST call to the Set Blob Properties API (http://msdn.microsoft.com/en-us/library/windowsazure/hh452235) to just turn off/on logging. I have gotten the REST API call to successfully work for retrieving Blob Properties, so I know my hashing algorithms, headers-setting, and Authentication signature creation works, but I can't seem to get it working on the Set Properties side of things. I keep getting an error on the Authentication Header, so I know I'm not doing something right there.
I have copied below what is being created and eventually hashed and put into the auth header string. The online documentation (http://msdn.microsoft.com/en-us/library/windowsazure/dd179428) does not really help in determining which of these fields are absolutely required for this particular type of Blob request, so I've tried filling most of them in, but I don't seem to get a difference response regardless of what I fill in. I've also tried the Shared Key Lite authentication, which would be preferred since it's much more lightweight, but that doesn't seem to work either when I fill in all 5 of those fields.
Shared Key Authentication for Blob Services:
PUT\n
\n
\n
130\n
(MD5_CONTENT_HASH)
\n
\n
\n
\n
\n
\n
\n
x-ms-date:Tue, 19 Jun 2012 19:53:58 GMT\n
x-ms-version:2009-09-19\n
/(MY_ACCOUNT)/\n
comp:properties\n
restype:service
Is there anything obvious I'm missing here? The values (MD5_CONTENT_HASH) and (MY_ACCOUNT) are of course filled in when I make the request call, and the similar request call to "GET" the properties works fine when I send it. The only difference between that one and this is that I'm sending the MD5_content, along with the content-length. I may be missing something obvious here, though.
Any advice would be greatly appreciated! Thanks in advance.
-Vincent
EDIT MORE INFO:
Programming Language I'm using: Objective-C (iOS iPhone)
I'm also using ASIHTTPRequest to make the request. I simply define the request, setRequestMethod:#"PUT", then I create the request body and convert it to NSData to calculate the length. I attach the request-body data via the appendPostData method to the request. I then build the auth string above, hash the whole thing, and attach it to the request as a header called "Authorization".
Request Body String I'm using:
<?xml version=\"1.0\" encoding=\"utf-8\"?><StorageServiceProperties><Logging><Version>1</Version></Logging></StorageServiceProperties>
I know this is an incomplete request body, but I was planning on waiting for it to give a failure on "missing request body element" or something similar, until I proceeded on creating the full XML there. (could that be my issue?)
Error I get from the server:
<?xml version="1.0" encoding="utf-8"?><Error><Code>AuthenticationFailed</Code><Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:accc4fac-2701-409c-b1a7-b3a528ce7e8a
Time:2012-06-20T14:36:50.5313236Z</Message><AuthenticationErrorDetail>The MAC signature found in the HTTP request '(MY_HASH)' is not the same as any computed signature. Server used following string to sign: 'POST
130
x-ms-date:Wed, 20 Jun 2012 14:36:50 GMT
x-ms-version:2009-09-19
/(MY_ACCOUNT)/
comp:properties
restype:service'.</AuthenticationErrorDetail></Error>
What's odd is that the error I get back from the server seems to look like that, no matter how many parameters I pass into the Authentication signature.
Thanks for any help you can offer!
Comparing your signed string and the error message indicates that you're sending a POST request but signing as though you're sending a PUT.