Codename One Curl Request oAuth - codenameone

I am trying to make a call to the Petfinder API from codename one. It requires oAuth authorization. Right now I am able to get access to the API from terminal, but I do not know how to call it from codename one which uses Java. Right now I'm able to pull data from APIs that don't need oAuth but need a key.
From terminal it looks like this:
curl -d "grant_type=client_credentials&client_id={CLIENT-ID}&client_secret={CLIENT-SECRET}" https://api.petfinder.com/v2/oauth2/token
{"token_type": "Bearer","expires_in": 3600,"access_token": "{my access token}"
}
curl -H "Authorization: Bearer {my access token}" GET https://api.petfinder.com/v2/animals?type=dog&page=2

You can use something like this. I haven't tested it though so debugging will be required:
Rest.post("https://api.petfinder.com/v2/oauth2/token").
queryParam("grant_type", "client_credentials").
queryParam("client_id", clientId).
queryParam("client_secret", clientSecret).
fetchAsJsonMap(response -> {
// data is already parsed to Map here
if(response.getResponseData() != null) {
accessToken = (String)response.getResponseData().get("access_token");
// set the auth header for all future requests in this session
addDefaultHeader("Authorization", "Bearer " + accessToken);
}
});
Notice that the code assumes a static import of the CN class exists. You could also store the token into Prefrences and load it dynamically/set it globally as I did here which is the more complete example.

Related

how to store bearer token in cookies in react js frontend

I am using React JS for the front-end part of my code. I want to store the bearer token in cookies and then return the bearer token in the content field when the API is called successfully. As I haven't used cookies earlier so want to know how I can accomplish this task. Also the back-end part is not done by me.
Following is the code in which I am calling the API
onSubmitSignup = () => {
fetch('https://cors-anywhere.herokuapp.com/http://35.154.16.105:8080/signup/checkMobile',{
method:'post',
headers:{'Content-Type':'application/json'},
body: JSON.stringify({
mobile:this.state.mobile
})
})
.then(response => response.json())
.then(data =>{
if(data.statusCode === '2000'){
localStorage.setItem('mobile',this.state.mobile);
// this.props.loadNewUser(this.state.mobile);
this.props.onRouteChange('otp','nonav');
}
})
// this.props.onRouteChange('otp','nonav');
}
First of all, on this line:
if(data.statusCode === '2000'){
Are you sure the status code shouldn't be 200 and not 2000.
Secondly, there are packages for managing cookies. One that springs to mind is:
Link to GitHub "Universal Cookie" repo
However you can use vanilla js to manage cookies, more info can be found on the Mozilla website:
Here
When you make that initial API call, within the data returned, I assume the Bearer token is returned too. Initialise the cookie there like so:
document.cookie = "Bearer=example-bearer-token;"
When you need access to the cookie at a later date, you can just use the following code:
const cookieValue = document.cookie
.split('; ')
.find(row => row.startsWith('Bearer'))
.split('=')[1];
And then forward the bearer with the next call.
Edit
Set the cookie bearer token like this:
document.cookie = "Bearer=example-bearer-token;"
Get the cookie bearer token like this:
const cookieValue = document.cookie
.split('; ')
.find(row => row.startsWith('Bearer'))
.split('=')[1];
A cookie is made up of key/value pairs separated by a semi-colon. Therefore the above code to get the "Bearer" value, firstly gets the cookie, splits it into its key/value pairs, finds the row that has a key of "Bearer" and splits that row to attain the Bearer token.
In your comment you say the dev team said the bearer will be in the "content". In your ajax request you already have access to that content through data. You need to debug that request to find out what it is coming back as. I assume you just need to grab the token from the returned data inside of the "If" block where you check for your statusCode.
It will be something like:
document.cookie = "Bearer=" + data.bearer;
However, I don't have the shape of your data so you can only work that final part out yourself.

How do I get data out of the Authorization header and use it in my API? (Lexik JWT)

I am in the process of making a SPA (hybrid app) using ionic and AngularJS (1.5.x). I am using Symfony 2.8 for my backoffice and to handle my API.
I wanted to use JWT, and i'm using the Lexik JWT package for it. Everything works fine. When the user logs in, he gets a token that is then saved in the Authorization header. Only users with this token (or rather token in this header) can access the API and do API calls.
The only thing which is unclear to me is how to make it so that the user can only do API calls (Get user information, update only their own posts or such) that concerns their OWN information.
So far I've tried to get the data out of the Authorization header to further on somehow use this token's data (username is in there) to check if it is equal to the user's name who has made this report.
Tried several things such as getallheaders(), $token = $_SERVER['Authorization']; and other general functions that check the request headers, but everytime I'm getting errors as well.
Am I misunderstanding something or am I missing a step? Am I incorrectly using JWT? Is my reasoning correct that this is how I should do it or is there a more fluent way/logical to do this?
I'm also using FOSRestBundle for my API as well as NelmioCORS, NelmioApiDoc and FOSUSERBundle
When your are behind the firewall provided by the bundle and if the user is correctly logged in, you can get the user object from your controller by calling the methods getToken() then getUser() of the security.token_storage service.
If your controller extends Symfony\Bundle\FrameworkBundle\Controller\Controller, you can directly call $this->getUser().
<?php
namespace AcmeBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
/**
* #Route("/api")
*/
class ApiController extends Controller
{
/**
* #Route("/hello")
* #Security("is_granted('ROLE_USER')")
*/
public function helloAction()
{
$token = $this->get('security.token_storage')->getToken();
$if (null !== $token) {
//$token should be an instance of Lexik\Bundle\JWTAuthenticationBundle\Security\Authentication\Token\JWTUserToken
$user = $token->getUser();
}
// or
$user = $this->getUser();
...
}
}

Quickbook No apptoken detected; (PHP)errorCode=003102; statusCode=401

I am new in quickbooks API implementation, I am always getting one error No apptoken detected; errorCode=003102; statusCode=401 when I am doing API call for customer add etc.
I am giving my steps, please look over that.
My sandbox info like that
Consumer Key: qyprdffbBBInX4a82jG73Mreyy96tC
Consumer Secret: IgpJzJrYvb9FmmdB7A0ECDGHG62Cp7dqVWjfMTvU
Access Token: qyprdlo3WrK0KhGZMTeA857AuKiVy2eaAmpXsRvG3jycYaMQ
Access Token Secret: TdPGpcUI8AiAdWFiCyb8jAAygH16bzU7VRGaspx4
I am Using PHP.
First I have generated oauth_signature.
$URL =
rawurlencode('https://sandbox-quickbooks.api.intuit.com/v3/company/408554291/customer');
$method = 'POST'; $parameter =
rawurlencode('oauth_consumer_key=qyprdffbBBInX4a82jG73Mreyy96tC&oauth_nonce=BlyqIBbv3R4T0P4qglAv1RjoYisMZk1449659733&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1449659733&oauth_token=qyprdlo3WrK0KhGZMTeA857AuKiVy2eaAmpXsRvG3jycYaMQ&oauth_version=1.0');
$ukey =
rawurlencode('IgpJzJrYvb9FmmdB7A0ECDGHG62Cp7dqVWjfMTvU').'&'.rawurlencode('TdPGpcUI8AiAdWFiCyb8jAAygH16bzU7VRGaspx4');
$hasmac = hash_hmac("sha1", $BaseURL,$ukey,1);
and My oauth_signature is jZ8JhECy/e0kpPbUdZp/o/EUC7U=
When i call API with this oauth_signature, i am getting Error 'No apptoken detected; errorCode=003102; statusCode=401'
My CURL call like this
curl -X POST -H 'Content-Type: application/json, Authorization: OAuth
oauth_token=qyprdlo3WrK0KhGZMTeA857AuKiVy2eaAmpXsRvG3jycYaMQ,oauth_consumer_key=qyprdffbBBInX4a82jG73Mreyy96tC,oauth_signature_method=HMAC-SHA1,oauth_timestamp=1449659733,oauth_version=1.0,oauth_nonce=BlyqIBbv3R4T0P4qglAv1RjoYisMZk1449659733,oauth_signature=jZ8JhECy/e0kpPbUdZp/o/EUC7U='
-d '{"data": [{"BillAddr":{"Line1":"86 A Topsia","City":"Kolkata","Country":"India","CountrySubDivisionCode":"WB","PostalCode":"700102"},"Title":"Mr.","GivenName":"ApurbaK","MiddleName":"Kumar","FamilyName":"ApurbaK","PrimaryPhone":{"FreeFormNumber":"564545465"},"PrimaryEmailAddr":{"Address":"apurbahazra12#navsoft.in"}}]}'
'https://sandbox-quickbooks.api.intuit.com/v3/company/408554291/customer'
Please look over that.
Thanks,
Apurba
Firstly, you don't want to be doing this yourself -- use a library. OAuth is complex, and implementing it yourself is going to be a hairy process, rife with errors.
Go grab a library:
https://github.com/consolibyte/quickbooks-php
Follow the quick-start guide linked there, and benefit from the examples:
https://github.com/consolibyte/quickbooks-php/tree/master/docs/partner_platform/example_app_ipp_v3
With that said, if you do decide to write it yourself, make sure you follow the OAuth spec:
https://www.rfc-editor.org/rfc/rfc5849
So far, the issues I immediately see with your implementation are:
You can't hard-code the timestamp like this: &oauth_timestamp=1449659733 The timestamp should be ever-changing, and set to the currenty timestamp.
You can't hard-code a nonce like this: &oauth_nonce=BlyqIBbv3R4T0P4qglAv1RjoYisMZk1449659733 The nonce has to change with every single request so this is going to fail after your first request.
You haven't normalized your request parameters / sorted them, per the spec.
This is the incorrect way to specify multiple headers with cURL: -H 'Content-Type: application/json, Authorization: OAuth .... Please see the cURL docs: http://curl.haxx.se/docs/manpage.html#-H
In the code you posted, you haven't actually set $BaseURL anywhere, so right now you're signing an empty string (unless you forgot to paste some code somewhere?)
What is $ukey set to? It doesn't appear to be defined in your code anywhere (did you forget to paste some code in?)

Only one auth mechanism allowed; only the X-Amz-Algorithm query parameter..?

I am trying to send a PUT request to an amazonS3 presigned URL. My request seems to be called twice even if I only have one PUT request. The first request returns 200 OK, the second one returns 400 Bad Request.
Here is my code:
var req = {
method: 'PUT',
url: presignedUrl,
headers: {
'Content-Type': 'text/csv'
},
data: <some file in base64 format>
};
$http(req).success(function(result) {
console.log('SUCCESS!');
}).error(function(error) {
console.log('FAILED!', error);
});
The 400 Bad Request error in more detail:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>InvalidArgument</Code>
<Message>Only one auth mechanism allowed; only the X-Amz-Algorithm query parameter, Signature query string parameter or the Authorization header should be specified</Message>
<ArgumentName>Authorization</ArgumentName>
<ArgumentValue>Bearer someToken</ArgumentValue>
<RequestId>someRequestId</RequestId>
<HostId>someHostId</HostId>
</Error>
What I don't understand is, why is it returning 400? and What's the workaround?
Your client is probably sending an initial request that uses an Authorization header, which is being responded with a 302. The response includes a Location header which has a Signature parameter. The problem is that the headers from the initial request are being copied into the subsequent redirect request, such that it contains both Authorization and Signature. If you remove the Authorization from the subsequent request you should be good.
This happened to me, but in a Java / HttpClient environment. I can provide details of the solution in Java, but unfortunately not for AngularJS.
For the Googlers, if you're sending a signed (signature v4) S3 request via Cloudfront and "Restrict Bucket Access" is set to "Yes" in your Cloudfront Origin settings, Cloudfront will add the Authorization header to your request and you'll get this error. Since you've already signed your request, though, you should be able to turn this setting off and not sacrifice any security.
I know this may be too late to answer, but like #mlohbihler said, the cause of this error for me was the Authorization header being sent by the http interceptor I had setup in Angular.
Essentially, I had not properly filtered out the AWS S3 domain so as to avoid it automatically getting the JWT authorization header.
Also, the 400 "invalid argument" may surface as a result of wrong config/credentials for your S3::Presigner that is presigning the url to begin with. Once you get past the 400, you may encounter a 501 "not implemented" response like I did. Was able to solve it by specifying a Content-Length header (specified here as a required header). Hopefully that helps #arjuncc, it solved my postman issue when testing s3 image uploads with a presigned url.
The message says that ONLY ONE authentication allowed. It could be that You are sending one in URL as auth parameters, another - in headers as Authorization header.
import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:scavenger_inc_flutter/utils/AuthUtils.dart';
import 'package:scavenger_inc_flutter/utils/URLS.dart';
class ApiClient {
static Dio dio;
static Dio getClient() {
if (dio == null) {
dio = new Dio();
dio.httpClientAdapter = new CustomHttpAdapter();
}
return dio;
}
}
class CustomHttpAdapter extends HttpClientAdapter {
DefaultHttpClientAdapter _adapter = DefaultHttpClientAdapter();
#override
void close({bool force = false}) {
_adapter.close(force: force);
}
#override
Future<ResponseBody> fetch(RequestOptions options,
Stream<List<int>> requestStream, Future<dynamic> cancelFuture) async {
String url = options.uri.toString();
if (url.contains(URLS.IP_ADDRESS) && await AuthUtils.isLoggedIn()) {
options.followRedirects = false;
options.headers.addAll({"Authorization": await AuthUtils.getJwtToken()});
}
final response = await _adapter.fetch(options, requestStream, cancelFuture);
if (response.statusCode == 302 || response.statusCode == 307) {
String redirect = (response.headers["location"][0]);
if(!redirect.contains(URLS.IP_ADDRESS)) {
options.path = redirect;
options.headers.clear();
}
return await fetch(options, requestStream, cancelFuture);
}
return response;
}
}
I disallowed following redirects.
Used the response object to check if it was redirected.
If it was 302, or 307, (HTTP Redirect Codes), I resent the request after clearing the Auth Headers.
I used an additioal check to send the headers only if the path contained my specific domain URL (or IP Address in this example).
All of the above, using a CustomHttpAdapter in Dio. Can also be used for images, by changing the ResponseType to bytes.
Let me know if this helps you!
I was using django restframework. I applied Token authentication in REST API. I use to pass token in request header (used ModHeader extension of Browser which automatically put Token in Authorization of request header) of django API till here every thing was fine.
But while making a click on Images/Files (which now shows the s3 URL). The Authorization automatically get passed. Thus the issue.
Link look similar to this.
https://.s3.amazonaws.com/media//small_image.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXXXXXXXXXXXXXXXXXXXX%2F20210317%2Fap-south-XXXXXXXXFaws4_request&X-Amz-Date=XXXXXXXXXXXXXXX&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
I lock the ModHeader extension to pass Authorization Token only while making rest to REST API and not while making resquest to S3 resources. i.e. do not pass any other Authorization while making request to S3 resource.
It's a silly mistake. But in case it helps.
Flutter: if you experience this with the http dart package, then upgrade to Flutter v2.10!
Related bugs in dart issue tracker:
https://github.com/dart-lang/sdk/issues/47246
https://github.com/dart-lang/sdk/issues/45410
--> these has been fixed in dart 2.16, which has been shipped with Flutter v2.10!
https://medium.com/dartlang/dart-2-16-improved-tooling-and-platform-handling-dd87abd6bad1

refreshToken is null

I used DREdit app's Oauth code to get accessToken and refreshToken for my app and i am getting the accessToken but refreshToken is coming null always.
I tried to print the values in the code which comes like below
authorization URL:https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=force&client_id=651991573332.apps.googleusercontent.com&redirect_uri=http://www.sakshum.org/GoogleOauth&response_type=code&scope=https://www.googleapis.com/auth/drive.file%20https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/userinfo.profile
This code already has access_type=offline which I found not having in the url was the cause in some cases. Please advise what else could be wrong here.
The log prints as follows on appEngine
[s~sakshumweb-hrd/3.368699522239285323].<stdout>: Code:4/XQ1sR1Pu5VHDqGbG9iJO10bXVCCE.Qn-L1XwrBVYaEnp6UAPFm0EmSoCXfwI
W 2013-07-10 20:20:16.294
com.google.api.client.googleapis.services.AbstractGoogleClient <init>: Application name is not set. Call Builder#setApplicationName.
I 2013-07-10 20:20:16.536
[s~sakshumweb-hrd/3.368699522239285323].<stdout>: id:113470899999229420779
I 2013-07-10 20:20:17.936
[s~sakshumweb-hrd/3.368699522239285323].<stdout>: access token:ya29.AHES6ZSP7MXaaUhMz4RO7Jm3Zkh_s1zUxJyzW_6IvfADaQ
I 2013-07-10 20:20:17.936
[s~sakshumweb-hrd/3.368699522239285323].<stdout>: refresh token:null
Refresh tokens are only issued on the initial authorization (whenever the consent screen is shown.) If you find you're in a state where you don't have a saved refresh token for a user, you can ask for reauthorization with the added query parameter prompt=consent. The user will be asked to re-authorize and a new refresh token will be generated.
After your link you get authorization code. For instance:
https://accounts.google.com/o/oauth2/auth?access_type=offline
&approval_prompt=auto
&client_id=[your id]
&redirect_uri=[url]
&response_type=code
&scope=[access scopes]
&state=/profile
then if in future you are going to have access to drive you need refresh token (you can every time request auth token - redirecting to google and etc... but it's not good way. after first usage, you should save Credentials in Database with User UID (for instance, it may be mail). So if you need to have access to the drive in the feature you do this:
static Credential exchangeCode(String authorizationCode)
throws CodeExchangeException {
try {
GoogleAuthorizationCodeFlow flow = getFlow();
GoogleTokenResponse response =
flow.newTokenRequest(authorizationCode).setRedirectUri(REDIRECT_URI).execute();
return flow.createAndStoreCredential(response, null);
} catch (IOException e) {
System.err.println("An error occurred: " + e);
throw new CodeExchangeException(null);
}
}
As I guess you also want to get url of the file which is in the Google Drive. when you get files - thee the documentation, then you will find download methids in com.google.api.services.drive.model.File object. read documentations

Resources