This is my code:
string accessToken = "##";
string accessTokenSecret = "##";
string consumerKey = "##";
string consumerSecret = "##";
string appToken = "##";
string realmId = "##"; //company id in quickbooks online
OAuthRequestValidator oauthValidator = new OAuthRequestValidator(accessToken, accessTokenSecret, consumerKey, consumerSecret);
ServiceContext context = new ServiceContext(oauthValidator, appToken, realmId, IntuitServicesType.QBO);
I am receiving: InvalidTokenException was unhandled by user code - {"Unauthorized"}
in the creating the new ServiceContext line. Not sure what the problem is.
Thanks for any help provided.
This error message:
InvalidTokenException was unhandled by user code - {"Unauthorized"}
Occurs when the OAuth tokens you're using are no longer valid.
I would double-check that:
You're using a valid set of OAuth tokens that you got from Intuit
The tokens are not expired (the Developer Playground tokens are very
short lived, longer-lived 6-month tokens are available if you set up
your own actual OAuth endpoint)
Here is Intuit's documentation for setting up your own OAuth endpoint:
http://docs.developer.intuit.com/0025_Intuit_Anywhere/0010_Getting_Started/0020_Connect/0010_From_Within_Your_App/Implement_OAuth_in_Your_App
Related
I have a legacy application written in VB6 (I Know!!) to which I am adding a DocuSign feature. I a using InterOp to run .NET code written is VS2019 VB.Net. The reason I am using 4.0.4.0 as this is the version I can successfully call using InterOp. I have all the code working except for requesting a JWT token. Does anyone have JWT code working under this version of the API ?
This is what I have working under later versions of DocuSign and am trying to replace
`Dim privatekey As Byte() = File.ReadAllBytes("docusign_private_key.key")
Dim result As Object = x.RequestJWTApplicationToken(gsSIGNERCLIENTID, docuSignAuthServer, privatekey, 1, scopes)
txtAccessToken.Text = result
'
' Second attempt at alternative
'
` Dim authToken As OAuth.OAuthToken = x.RequestJWTUserToken(gsSIGNERCLIENTID, gsUserIDGUID, docuSignAuthServer, privatekey, 1)
txtAccessToken.Text = authToken.access_token`
'
' Third attempt
'
Dim request = TryCast(System.Net.WebRequest.Create("https://account-d.docusign.com/oauth/token"), System.Net.HttpWebRequest)
request.Method = "POST"
request.Headers.Add("username", "user123")
request.Headers.Add("password", "123")
request.Headers.Add("auth_access_type", "read")
request.ContentLength = 0
Dim responseContent As String = ""
Using response = TryCast(request.GetResponse(), System.Net.HttpWebResponse)
Using reader = New System.IO.StreamReader(response.GetResponseStream())
responseContent = reader.ReadToEnd()
End Using
End Using
'
' Fifth attempt
'
Dim apiClient5 As New ApiClient(gsBASEPATH)
Dim authToken5 As OAuth.OAuthToken = apiClient5.RequestJWTUserToken(gsINTEGRATIONKEY, gsUserIDGUID, "https://account-d.docusign.com/oauth/token", privatekey, 1, scopes)
All results in 'Error while requesting server, received a non-successful HTPC code Error with response Body'
Your second attempt is correct:
Dim authToken As OAuth.OAuthToken = x.RequestJWTUserToken(gsSIGNERCLIENTID, gsUserIDGUID, docuSignAuthServer, privatekey, 1)
txtAccessToken.Text = authToken.access_token
AuthServer has to be "account-d.docusign.com"
The privateKey has to be the exact thing you got from DocuSign, including the new lines and all. To get it use this code:
File.ReadAllBytes(path) where path is the path on the disk to a plain text file with your private key.
gsSIGNERCLIENTID should be the GUID for the user that you use that has consent. You must make sure user gave consent by building a consent URL as explained in here:
https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/
If you did all of this correctly - it should work.
I'm building an oauth2 client with Flask and Authlib. My code to register the oauth is:
google = oauth.register(
name='google',
client_id='',
client_secret="",
access_token_url="https://accounts.google.com/o/oauth2/token",
access_token_params=None,
authorize_url="https://accounts.google.com/o/oauth2/auth",
authorize_params=None,
api_base_url="https://www.googleapis.com/oauth2/v1/",
client_kwargs={'scope': 'openid email'},
server_metadata_url="https://accounts.google.com/.well-known/openid-configuration",
)
And my /authorize endpoint looks like this:
#app.route('/authorize')
def authorize():
google = oauth.create_client('google')
token = google.authorize_access_token()
resp = google.get('userinfo')
resp.raise_for_status()
userinfo = resp.json()
return str(userinfo)
But I am getting the error
authlib.jose.errors.InvalidClaimError: invalid_claim: Invalid claim "iss"
I had this issue and removing the openid value from scope fixed it. I guess my google config didn't accomodate it,
I tried to generate the token which can be used as the HTTP header to authenticate to the HDFS WebHDFS URL and Oozie REST API URL.
I referenced the url below to have the below code to generate the Negotiate token.
https://www.ibm.com/support/knowledgecenter/en/SS7JFU_8.5.5/com.ibm.websphere.express.doc/ae/tsec_SPNEGO_token.html
public class TokenCreation {
private static final String SPNEGO_OID = "1.3.6.1.5.5.2";
private static final String KERBEROS_OID = "1.2.840.113554.1.2.2";
public static byte[] genToken(String principal) {
System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
byte[] spnegoToken = new byte[0];
try {
Oid spnegoMechOid = new Oid(SPNEGO_OID);
Oid krb5MechOid = new Oid(KERBEROS_OID);
GSSCredential clientGssCreds = null;
GSSManager manager = GSSManager.getInstance();
GSSName gssUserName = manager.createName(principal, GSSName.NT_USER_NAME, krb5MechOid);
clientGssCreds = manager.createCredential(gssUserName.canonicalize(krb5MechOid),
GSSCredential.INDEFINITE_LIFETIME,
krb5MechOid,
GSSCredential.INITIATE_ONLY);
clientGssCreds.add(gssUserName,
GSSCredential.INDEFINITE_LIFETIME,
GSSCredential.INDEFINITE_LIFETIME,
spnegoMechOid, GSSCredential.INITIATE_ONLY);
GSSName gssServerName = manager.createName(principal, GSSName.NT_USER_NAME);
GSSContext clientContext = manager.createContext(gssServerName.canonicalize(spnegoMechOid),
spnegoMechOid,
clientGssCreds,
GSSContext.DEFAULT_LIFETIME);
// optional enable GSS credential delegation
clientContext.requestCredDeleg(true);
// create a SPNEGO token for the target server
spnegoToken = clientContext.initSecContext(spnegoToken, 0, spnegoToken.length);
} catch (GSSException e) {
e.printStackTrace();
}
return spnegoToken;
}
But after running the above code, I always got the below prompt:
2019-09-25 14:12:51 760 [INFO] [pool-2-thread-1] c.s.n.c.u.security.KrbUtils - after loginUserFromKeytab............AtoimcUser:HTTP/host1.exmaple.com#EXAMPLE.COM
2019-09-25 14:12:51 760 [INFO] [pool-2-thread-1] c.s.n.app.oozie.OozieAppCaller - ->>>>>>User Name is HTTP/host1.exmaple.com#EXAMPLE.COM
2019-09-25 14:12:51 760 [INFO] [pool-2-thread-1] c.s.n.app.oozie.OozieAppCaller - ->>>>>>Mode is KERBEROS
>>>KinitOptions cache name is /tmp/krb5cc_0
Kerberos username [root]: ^C^C^C
Kerberos password for root:
You can see at the end of the above output log.
The "Kerberos username" is always prompt to ask for username.
Also I have tried to manually run kinit the keytab.
and the above class can generate the token successfully.
But manually run kinit is NOT the way I wanted.
Would you please help it?
Thanks.
Kerberos and SPNEGO support in Java is cumbersome unfortunately.
I've created a small library to simplify some Kerberos use cases: https://github.com/bedrin/kerb4j
You can use it like this to generate SPNEGO token:
SpnegoClient spnegoClient = SpnegoClient.loginWithKeyTab("svc_consumer", "/opt/myapp/consumer.keytab");
URL url = new URL("http://api.provider.acme.com/api/operation1");
SpnegoContext context = spnegoClient.createContext("http://provider.acme.com"); // Will result in HTTP/provider.acme.com SPN
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("Authorization", context.createTokenAsAuthroizationHeader());
my server is Flask based, my client is android studio, and i'm communication using retrofit.
The problem is that i'm not able to pass the jwt token correctly from the android to the server after logging in.
With postman it's working good:
{{url}}/auth - I'm logging in as the user, and getting the JWT token.
Later i'm adding "Authorization" header, with the Value "JWT {{jwt_token}}" and
{{url}}/users/john - I'm asking for user info, which is recieved without problems.
The endpoint from android studio:
public interface RunnerUserEndPoints {
// #Headers("Authorization")
#GET("/users/{user}")
Call<RunnerUser> getUser(#Header("Authorization") String authHeader, #Path("user") String user);
The call itself (The access_token is correct before sending!):
final RunnerUserEndPoints apiService = APIClient.getClient().create(RunnerUserEndPoints.class);
Log.i("ACCESS","Going to send get request with access token: " + access_token);
Call<RunnerUser> call = apiService.getUser("JWT" + access_token, username);
Log.i("DEBUG","Got call at loadData");
call.enqueue(new Callback<RunnerUser>() {
#Override
public void onResponse(Call<RunnerUser> call, Response<RunnerUser> response) { ....
The response error log from the server:
File "C:\Users\Yonatan Bitton\RestfulEnv\lib\site-packages\flask_restful\__init__.py", line 595, in dispatch_request
resp = meth(*args, **kwargs)
File "C:\Users\Yonatan Bitton\RestfulEnv\lib\site-packages\flask_jwt\__init__.py", line 176, in decorator
_jwt_required(realm or current_app.config['JWT_DEFAULT_REALM'])
File "C:\Users\Yonatan Bitton\RestfulEnv\lib\site-packages\flask_jwt\__init__.py", line 151, in _jwt_required
token = _jwt.request_callback()
File "C:\Users\Yonatan Bitton\RestfulEnv\lib\site-packages\flask_jwt\__init__.py", line 104, in _default_request_handler
raise JWTError('Invalid JWT header', 'Unsupported authorization type')
flask_jwt.JWTError: Invalid JWT header. Unsupported authorization type
10.0.0.6 - - [30/Sep/2017 01:46:11] "GET /users/john HTTP/1.1" 500 -
My api-client
public class APIClient {
public static final String BASE_URL = "http://10.0.0.2:8000";
private static Retrofit retrofit = null;
public static Retrofit getClient(){
if (retrofit==null){
retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
Log.i("DEBUG APIClient","CREATED CLIENT");
return retrofit;
}
}
Actually i'm really stuck. Tried to follow along all of the tutorials at retrofit's website without success.
I'm sure that there is a simple solution, I just need to add "Authorization" Header with Value "JWT " + access_token like it works in postman and that's it! Thanks.
EDIT:
The problem was the build of the access_token in my client.
I did:
JsonElement ans = response.body().get("access_token");
access_token = "JWT " + ans.toString();
Which I should have done:
JsonElement ans = response.body().get("access_token");
access_token = "JWT " + ans.getAsString();
So before it sent "JWT "ey..." " (Double "" )
And now it sends "JWT ey ... "
Let's start to look at what we know about the problem.
We know that the request is sent
We know that the server processes the request
We know that the JWT is invalid thanks to the error:
JWTError('Invalid JWT header', 'Unsupported authorization type')
If we look for that error in the flask_jwt source code, we can see that this is where our error is raised:
def _default_request_handler():
auth_header_value = request.headers.get('Authorization', None)
auth_header_prefix = current_app.config['JWT_AUTH_HEADER_PREFIX']
if not auth_header_value:
return
parts = auth_header_value.split()
if parts[0].lower() != auth_header_prefix.lower():
raise JWTError('Invalid JWT header', 'Unsupported authorization type')
elif len(parts) == 1:
raise JWTError('Invalid JWT header', 'Token missing')
elif len(parts) > 2:
raise JWTError('Invalid JWT header', 'Token contains spaces')
return parts[1]
Basically flask_jwt takes the Authorization header value and tries to split it into two. The function split can split a string by a delimiter, but if you call it without a delimiter it will use whitespace.
That tells us that flask_jwt expects a string that contains 2 parts separated by whitespace, such as space, and that the first part must match the prefix we are using (in this case JWT).
If we go back and look at your client code, we can see that when you are building the value to be put in the Authorization header you are not adding a space between JWT and the actual token:
apiService.getUser("JWT" + access_token, username);
This is what you should have been doing:
apiService.getUser("JWT " + access_token, username);
Notice the space after JWT?
I am trying to write automated tests for a REST API using apache HTTP client, we are using Facebook as an affiliate to log in.
I have used this question as a starting point:
apache HttpClient to access facebook
But it is using lots of deprecated methods.
I have switched all of these out but I am finding that it is not working.
to validate I have written a method to print out the body response and I am viewing that by making it into a HTML document. When I load that page it has the facebook error message of:
Cookies Required
Cookies are not enabled on your browser. Please enable cookies in your browser preferences to continue.
My code:
CookieStore cs = new BasicCookieStore();
HttpClientContext context = HttpClientContext.create();
HttpGet httpget = new HttpGet("http://www.facebook.com/login.php");
HttpResponse response= HttpClientBuilder.create().setDefaultCookieStore(cs).build().execute(httpget);
System.out.println("Login form get: " + response.getStatusLine());
HttpPost httpost = new HttpPost("https://www.facebook.com/login.php");
context.setCookieStore(cs);
List <NameValuePair> nvps = new ArrayList <NameValuePair>();
nvps.add(new BasicNameValuePair("email", "******"));
nvps.add(new BasicNameValuePair("pass", "*****"));
nvps.add(new BasicNameValuePair("lsd", "AVptst2v"));
httpost.setHeader("User-Agent", "Mozilla/5.0");
httpost.setHeader("Host", "www.facebook.com");
httpost.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
httpost.setHeader("Accept-Language", "en-US,en;q=0.5");
httpost.setHeader("Cookie", cs.toString());
httpost.setHeader("Connection", "keep-alive");
httpost.setHeader("Referer", "https://www.facebook.com/login");
httpost.setHeader("Content-Type", "application/x-www-form-urlencoded");
httpost.setEntity(new UrlEncodedFormEntity(nvps));
response = HttpClientBuilder.create().setDefaultCookieStore(cs).build().execute(httpost,context);
System.out.println("Login form post: " + response.getStatusLine());
System.out.println(printBodyOfResponse(response));
To answer my own question, I found that creating a context and passing that through with each request carried the session, I see lots of answers saying that cookie management is automatic, but for me the only solution was to pass the context throughout
BasicHttpContext context = new BasicHttpContext();
HttpGet get = new HttpGet("http://www.facebook.com/login.php");
HttpResponse response= HttpClientBuilder.create().build().execute(get,context);
System.out.println("Login form get: " + response.getStatusLine());
HttpPost httpost = new HttpPost("https://www.facebook.com/login.php?login_attempt=1");
List <NameValuePair> nvps = new ArrayList <NameValuePair>();
nvps.add(new BasicNameValuePair("email",PropertiesUtil.loadSiteProperty("FB_email")));
nvps.add(new BasicNameValuePair("pass", PropertiesUtil.loadSiteProperty("FB_password")));
httpost.setHeader("User-Agent", "Mozilla/5.0");
httpost.setHeader("Host", "www.facebook.com");
httpost.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
httpost.setHeader("Accept-Language", "en-US,en;q=0.5");
httpost.setHeader("Connection", "keep-alive");
httpost.setHeader("Referer", "https://www.facebook.com/login");
httpost.setHeader("Content-Type", "application/x-www-form-urlencoded");
httpost.setEntity(new UrlEncodedFormEntity(nvps));
response = HttpClientBuilder.create().build().execute(httpost,context);