How do I sign access token request withings oauth 1.0 - oauth

I am currently working on connecting the withings api via web and have been able to automate getting token secret and getting the userId from the callback function inside auth, however when trying to implement step 3 (generating token) I always get signing error. Here is the base logic please help if possible.
nonce = getNonce(32);
date = Math.round((new Date()).getTime() / 1000.0);
var requestSig = oauthSign.hmacsign(
'GET',
'https://oauth.withings.com/account/access_token',
{oauth_consumer_key: <myconsumerkey>,
oauth_nonce: nonce,
oauth_signature_method: 'HMAC-SHA1',
oauth_timestamp: date.toString(),
oauth_token: oauth_token,
oauth_version: '1.0'
}, newSecret);
var hey = encodeURIComponent(requestSig);
var permanentTokensLink = "https://oauth.withings.com/account/access_token?oauth_consumer_key=<myconsumerkey>&oauth_nonce="+nonce+"&oauth_signature="+hey+"&oauth_signature_method=HMAC-SHA1&oauth_timestamp="+date+"&oauth_token="+oauth_token+"&oauth_version=1.0";
return {link:permanentTokensLink, newSecret: newSecret, tokensecret: oauth_token_secret, dataObj: dataObj, token: oauth_token};
newSecrect is a consumersercret&tokensecret, and permanentTokensLink is where I should be able to click to to get the access key and secret. Why is this not working?

I was missing an oauth verifier in the signing params and inside the link I was creating, and the secret should have been broken up into two parts (consumer-secret, token-secret) to be used correctly by the npm package hmacsign.

Related

What auth flow to use with spa and service account msal

There's so many different flows in the Microsoft docs that I have no clue what one is needed for me. I am using React and Python. (I understand node, so if someone explains using node/express its fine)
What user should see:
A page with a button to login, nav is there but wont work till logged in. The login creates a popup to sign in with Microsoft account. Once signed in, the user will be able to use nav to see dynamics information.
What I am trying to do:
This app needs to sign in a user and obtain the users email through 'https://graph.microsoft.com/v1.0/me'.(no client secrets needed) Then I need to send that email in this request;
(The tenant == {company}.crm.dynamics.com.)
allInfo = requests.get(
f'https://{TENANT}api/data/v9.0/company_partneruserses?$filter=company_email eq \'{email}\'', headers=headers).json()
This backend request needs to have a client secret to obtain the information. So I believe my backend also needs to be logged on to a service account. I believe I need to get a token for my backend to make requests on behalf of the service account.
What I have:
I have a React frontend that is signing a user in and calling 'https://graph.microsoft.com/v1.0/me' correctly and getting that email. Once I get the email, I am sending it to my backend.
Now I have no clue how to proceed and have tried many things.
What I have tried for backend:
Attempt 1: I get a token but error: {'error': {'code': '0x80072560', 'message': 'The user is not a member of the organization.'}}. Problem is, this id is the Azure AD ID. It should def work
#app.route('/dynToken', methods=['POST'])
def get_dyn_token():
req = request.get_json()
partnerEmail = req['partnerEmail']
token = req['accessToken']
body = {
"client_id": microsoft_client_id,
"client_secret": client_secret,
"grant_type": "client_credentials",
"scope": SCOPE_DYN,
}
TENANTID = '{hash here}'
res = requests.post(
f'https://login.microsoftonline.com/{TENANTID}/oauth2/v2.0/token', data=body).json()
dyn_token = res['access_token']
headers = {
"Prefer": "odata.include-annotations=\"*\"",
"content-type": "application/json; odata.metadata=full",
"Authorization": f"Bearer {dyn_token}"
}
try:
allInfo = requests.get(
f'https://{TENANT}api/data/v9.0/company_partneruserses?$filter=company_email eq \'{email}\'', headers=headers).json()
print(allInfo)
Attempt 2:
Same code but instead of f'https://login.microsoftonline.com/{TENANTID}/oauth2/v2.0/token' its
f'https://login.microsoftonline.com/common/oauth2/v2.0/token'. Error: An exception occurred: [Errno Expecting value] : 0. Because it returns an empty string.
Now I don't know if I am even on the right path or where to go. I know the routes work themselves if the token is correct. I used only SSR with no react and these routes work. But I need the React to be there too. I just don't know what flow to use here to get what I need. The docs make it easy for /me route to work. But the {company}crm.dynamics.com docs don't really provide what I am trying to do.
Additional info after comment:
What 'f'https://{TENANT}api/data/v9.0/company_partneruserses?$filter=company_email eq '{email}'', headers=headers" is trying to get are API keys. Full code :
try:
allInfo = requests.get(
f'https://{TENANT}api/data/v9.0/company_partneruserses?$filter=company_email eq \'{email}\'', headers=headers).json()
partner_value = allInfo['value'][0]['_company_partner_value']
response = requests.get(
f'https://{TENANT}api/data/v9.0/company_partnerses({partner_value})', headers=headers).json()
return {'key': response['company_apikey'], 'secret': response['company_apisecret']}
Then once it has the keys:
def api_authentication(apikey, apisecret):
headers = get_headers() #<-- same headers as above with using dyn_token
response = requests.get(
f'https://{TENANT}api/data/v9.0/company_partnerses?$filter=company_apikey eq \'{apikey}\' and company_apisecret eq \'{apisecret}\'&$select=company_apikey,company_apisecret,_company_account_value,_company_primarycontact_value,blahblah_unassignedhours,company_reporturl', headers=headers).json()
return response
Afterwards I am able to get all the information I am looking for to send back to my frontend for the client to see. (By making multiple request to crm with these keys)
The client_credentials grant that you are using should work, provided the CRM trusts the token issued to the client (your python backend). Please use MSAL library instead of hand crafting the token request. It will save you time and eliminate errors.

Youtube oAuth promts authorization window every time I make request

Here is my work flow for getting access token and refresh token for youtube api. Im generating authorization url with parameters
access_type=offline, response_type=code, redirect_uri=uri, scope=scopes, state=state, client_id=id
from authorization url I´m receiving authentication code, then I´m generating another url to get access_token and refresh_token using code from authorization url with these parameters
code: code, client_id: CLIENT_ID, client_secret: CLIENT_SECRET, redirect_uri: serviceCallback, state: state.callback, grant_type: "authorization_code"
As far as I know user should complete this process only once and then it should be automatic. My problem is that I´m always have to complete authorization and I´m getting always new access_token and refresh_token without forcing it on request.
here is code part where I´m getting authentication url
getAuthUrl: function(scopes, applicationCallback, serviceCallback, siteId,
selectChannel, websiteUrl) {
var requestedClientId = CLIENT_ID;
var scopess =
"https://www.googleapis.com/auth/yt-analytics.readonly https://www.googleapis.com/auth/youtube.readonly https://www.googleapis.com/auth/userinfo.email " +
scopes.replace(",", " ");
return "https://accounts.google.com/o/oauth2/auth?" +
"access_type=offline" +
"&response_type=code" +
/*"&approval_prompt=auto" +*/
"&redirect_uri=" + serviceCallback +
"&scope=" + scopes +
"&state=" + JSON.stringify({
service: NAME,
callback: applicationCallback,
scopes: scopes,
siteId: siteId,
selectChannel: selectChannel,
websiteUrl: websiteUrl
}) +
"&client_id=" + requestedClientId;
},
From there Im getting back code and using that code, clientID and clientSecret to get access token and refresh token
getAuthTokens: function(code, state, res, serviceCallback) {
// Google oAuth endpoint
var endpoint = "https://www.googleapis.com/oauth2/v4/token";
const scopes = state.scopes.split(" ");
// Setup request data
var data = {
code: code,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
redirect_uri: serviceCallback,
state: state.callback,
grant_type: "authorization_code"
};
request.post(endpoint).send(data).type('form').set('Accept',
'application/json').end(function(err, oAuthResponse) {});
},
I was using wrong endpoint url I changed it to different one to one provided by youtube api documentation and removed state parameter from data variable but still doesnt fix the problem
new endpoint url
var endpoint = "https://accounts.google.com/o/oauth2/token";
I´m really confused right now because I´m not forcing authorization and on google apps section there is my app already authorized and it does not update authorization that means it gives permission only first time and after that when I´m pressing allow it doesn´t do anything. OAuth should check if I have refresh token or not, so my conclusion is that I don´t fully understand how it should work or I´m somehow testing everything on debug or test mode where authorization prompt is automatically forced.
I would be really thankful for any kind of help because I feel like I tried everything.
The issue is that the access token that you are using has expired before the next time you use as you have not updated the access token manually using the refresh token.
You need to use the refresh token to update the access token if [ (time you last updated the access token) + (the expiry time) ] has already surpassed.
The concept of refresh tokens is that if an access token is compromised, as it is short-lived, the attacker has a limited time period in which it can be used. Refresh tokens, if compromised, are useless because the attacker requires the client id and client secret in addition to the refresh token in order to gain an access token.
The YouTube API documentation demonstrates the procedure here
By default, the expiry time is around 3 seconds.
This will surely, work in your case.
Adding the following parameter to your authentication object may help...depending on your requirements:
prompt: 'none'
This would mean no consent is gained or needed, after an initial authorization to use the app.
Go to the my accounts settings of google for this account---> go to connected apps and sites ----> manage apps:
Over there can you see the permissions for youtube like this:

Ruby OAuth with Salesforce not getting refresh_token

I can't seem to get a refresh_token whenever I'm authorized, I've tried setting headers, kind of like how it would be done with google oauth, but not luck. Here's my process:
Using oauth2 gem
Instantiate client
client = OAuth2::Client.new(
salesforce_app_key,
salesforce_secret_key,
site: 'https://login.salesforce.com/services/oauth2/',
authorize_url: 'https://login.salesforce.com/services/oauth2/authorize',
token_url: 'https://login.salesforce.com/services/oauth2/token',
raise_errors: false
)
Authorize connection
auth = client.auth_code.authorize_url(
redirect_uri: 'https://my_app_callback.com/oauth/authorize'
)
Fetch token
token = client.auth_code.get_token(
code,
redirect_uri: 'https://my_app_callback.com/oauth/authorize'
)
From this point, I have the connection set, but when I do token.refresh_token I get a nil value.
By using:
access_token = OAuth2::AccessToken.new(oauth, token)
The session was reestablished successfully. It's in the docs, but not written in a way I could uderstand it's used to reauthenticate.

Issue exchanging LInkedIn javascript token to rest oauth token

I am using the article located at https://developer-programs.linkedin.com/documents/exchange-jsapi-tokens-rest-api-oauth-tokens to exchange my Javascript access token to a REST OAuth token.
After following the directions here, no matter what I seem to do, I only get a 400 Bad Request response back.
The flow I use for Facebook and want to recreate with LinkedIn is; front end authenticates to LinkedIn and passes an access token to my API, the API then gets all necessary user information and passes my own bearer token back to the client, et voila.
Unfortunately LinkedIn doesn't play so nicely with this, and I need to convert my token to an OAuth token from its Javascript token.
I pass the cookie LinkedIn gives me to my API, it looks something like the below (where OAuthBase is http://oauth.googlecode.com/svn/code/csharp/OAuthBase.cs)
access_token: "oxmKI9aU4RCfksdegZ3obZGHK-vo6Q4-4FSQk"
member_id: "AmjWCF7ExN"
signature: "t8KEbLjJ+r6uM42tUwfJm5yWp70="
signature_method: "HMAC-SHA1"
signature_order: ["access_token","member_id"]
signature_version: "1"
I then am attempting to make a call to https://api.linkedin.com/uas/oauth/accessToken to do the actual exchange. My code for this is:
public async Task<IHttpActionResult> ConvertLinkedInToken(LinkedInCovertTokenObject val)
{
string normalizeduri;
string normalizedparams;
OAuthBase o = new OAuthBase();
string signature = o.GenerateSignature(new Uri("https://api.linkedin.com/uas/oauth/accessToken"), Startup.linkedInAuthOptions.ClientId, Startup.linkedInAuthOptions.ClientSecret, val.access_token, null, "POST", o.GenerateTimeStamp(), o.GenerateNonce(), out normalizeduri, out normalizedparams);
var client = new HttpClient();
var uri = new Uri("https://api.linkedin.com/uas/oauth/accessToken?" +
"oauth_consumer_key=" + Startup.linkedInAuthOptions.ClientId +
"&xoauth_oauth2_access_token=" + val.access_token +
"&signature_method=HMAC-SHA1" +
"&signature=" + signature
);
var response = await client.GetAsync(uri);
return Ok();
}
No matter how I play around all I get back from LinkedIn is a 400 Bad Request without any other useful information.
1) How can I convert LinkedIn JS token to Rest OAuth token in my c# api
This is how I achieved that:
On the frontend:
IN.User.authorize(function(){
// here you can find oauth token
var oauth_token = IN.ENV.auth.oauth_token;
// send this token to your API endpoint
});
On your API (curl example), of course replace OAUTH_TOKEN with token received on the frontend.
curl -X GET \
'https://api.linkedin.com/v1/people/~:
(id,firstName,lastName,siteStandardProfileRequest,picture-url,email-
address)?format=json' \
-H 'oauth_token: OAUTH_TOKEN'
You are looking at old documentation from LinkedIn. Starting from 12th May, LinkedIn has started rolling out new changes in their API which includes authentication. In my knowledge, LinkedIn is not using OAuth anymore, and you need OAuth2.0 henceforth for authentication. You should check this link for more information:
https://developer.linkedin.com/docs/signin-with-linkedin

Trouble making authenticated calls to Bitbucket API via OAuth

I'm trying to make authenticated calls to the Bitbucket REST API, with Oauth authentication. I've successfully retrieved an oauth_token and an oauth_token_secret (although they are the same as the request_token and request_token_secret, which seems strange but not outside of the spec). When I make an API call to another endpoint, I get a 401 (not authenticated). I've tried using header authentication and/or passing the oauth_token and oauth_token_secret as HTTP params with the sane result.
Here's the code:
account_name_url = 'https://api.bitbucket.org/1.0/user'
feedback_oauth_hook = OAuthHook(
access_token='REDACTED',
access_token_secret='ALSO_REDACTED',
consumer_key=CLIENT_ID,
consumer_secret=CLIENT_SECRET,
header_auth=True
)
params = {
'access_token': auth_tokens['access_token'],
'access_token_secret': auth_tokens['access_secret']
}
response = requests.get(account_name_url, data=params, hooks={'pre_request': feedback_oauth_hook})
import oauth2 #pip install oauth2
accessToken = oauth2.Token(OAUTH_TOKEN, OAUTH_TOKEN_SECRET)
consumer_key = YOUR_COMSUMER_KEY
consumer_secret = YOUR_CONSUMER_SECRET
consumer = oauth2.Consumer(consumer_key, consumer_secret)
client = oauth2.Client(consumer, accessToken)
api_url = "https://api.bitbucket.org/1.0/user"
resp, content = client.request(api_url, "GET")
print resp, content
The above python code works for me.
I print the request info, notice that it contains oauth_version=1.0 which is required.
I tried removing it, then 401 was returned. I think BitBucket should document this.

Resources