Python requests to access OAUTH website content - SNL Finance - python

I've been banging my head up against the wall trying to retrieve content from the news source "SNL Finance". I have valid credentials, so in theory I should be able to programmatically access their news content.
In short, I've tried executing the below script but with no success:
s = requests.Session()
client_id = "..."
client_secret = "..."
token_url = "https://www.snl.com/SNL.Services.Security.Service/oauth/token"
protected_url = "https://www.snl.com/web/client?auth=inherit#news/article?id=40666532&KeyProductLinkType=14"
request_data = {
"client_id": client_id,
"client_secret": client_secret,
"scope": "https://www.snl.com",
"grant_type": "refresh_token",
"refresh_token": refresh_token
}
token_response = s.post(token_url, data=request_data)
### token response is in jwt format, including token_type, expires_in, scope, etc. ###
token = json.loads(token_response.text)["access_token"].split('>')[1].split('<')[0]
request_data["token"] = token
article = s.post(protected_url, headers=request_data)
Sadly, this fails. I end up with a 200 response, but it appears to just be the login page (honestly not entirely sure what I'm looking at).
For more background, I've included browser information as it populates throughout the authentication process:
Attempt to visit protected url, redirected to the below url (omitted snl base):
/web/client?auth=inherit&contextType=external&username=string&enablePersistentLogin=true&OverrideRetryLimit=0&SwitchGetToPostLimit=50000&contextValue=%2Foam&password=secure_string&challenge_url=https%3A%2F%2Fwww.snl.com%2Fweb%2Fclient%3Fauth%3Dinherit&request_id=-6149669210818920852&authn_try_count=0&locale=en_US&resource_url=https%253A%252F%252Fwww.snl.com%252FInteractiveX%252FDefault.aspx%253Ftarget%253Dnews%25252Farticle%25253Fid%25253D40666532%252526KeyProductLinkType%25253D14%2526SNL3%253D1
Request headers are shown here.
Upon entering login / password, a token is retrieved and the protected page loads.
Request cookies are as shown here.
Also, I'm a bit confused at to why the token value of SNL_OAUTH_TOKEN in the above link (second link) differs from what is shown in the jwt token response I receive from my script.
Any guidance here will be hugely appreciated. I'm also happy to send any other non-personal information that proves useful.
Thank you!

I ended up figuring this out. I underestimated Python's requests library.
It appears to be as easy as this:
# prep token request data
request_data = {
"client_id": client_id,
"client_secret": client_secret,
"scope": "https://www.snl.com",
"grant_type": "refresh_token",
"refresh_token": new_refresh_token
}
# post to token url with token credentials
# the request object stores the token response cookies
r1 = requests.post(token_url, data=request_data)
# post to protected url by setting cookies arg as cookies from previous response
r2 = requests.post(protected_url, cookies=r1.cookies)

Related

When I try to change volume with Spotify API, I get error code 403

When I try to change the volume, I get:
requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: https://api.spotify.com/v1/me/player/volume
I checked if my client_id and client_secret, everything seems fine. Also I have premium account.
import requests
from client_secrets import client_id, client_secret
AUTH_URL = 'https://accounts.spotify.com/api/token'
# POST
auth_response = requests.post(AUTH_URL, {
'grant_type': 'client_credentials',
"scope": "user-modify-playback-state",
'client_id': client_id,
'client_secret': client_secret,
})
# convert the response to JSON
auth_response_data = auth_response.json()
# save the access token
access_token = auth_response_data['access_token']
headers = {
'Authorization': 'Bearer {token}'.format(token=access_token)
}
data = {"volume_percent": 10}
response = requests.put("https://api.spotify.com/v1/me/player/volume",data=data, headers=headers)
response.raise_for_status()
Several authorization flows are detailed in their documentation but your request doesn't match any of them. If I understand correctly your app is just a server-side code without any frontend which means that the Client Credentials Flow is the one that best matches your need. In this flow you don't need to send the client ID and secret in the request body instead, you need to send them in the Authorization header in the following format: Basic <base64 encoded client_id:client_secret>.
Also, make sure to set the Content-Type header to application/x-www-form-urlencoded as stated in the documentation.
Otherwise, the rest seems fine.

Spotify API get user saved tracks error 401 missing token

I'm building a discord bot with discord.py and I'm trying to get the spotify user saved tracks.
This is my auth def:
#classmethod
def get_token(self):
CLIENT_ID = 'myclientid'
CLIENT_SECRET = "myclientsecret"
SPOTIFY_TOKEN_URL = "https://accounts.spotify.com/api/token"
client_token = base64.b64encode("{}:{}".format(CLIENT_ID, CLIENT_SECRET).encode('UTF-8')).decode('ascii')
headers = {"Authorization": "Basic {}".format(client_token)}
payload = {"grant_type": "client_credentials"}
token_request = requests.post(SPOTIFY_TOKEN_URL, data=payload, headers=headers)
access_token = json.loads(token_request.text)["access_token"]
return access_token
This is my def where I try to get the user saved tracks:
#commands.command(name='splayfav', aliases=['splayfavorites', 'splaysavedtracks'], description="Command to see the info from spotify \n __Example:__ \u200b \u200b *!infos*")
async def play_saved_tracks_from_spotify(self, ctx):
token = self.get_token(ctx)
headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': f'Bearer {token}',
}
response = requests.get('https://api.spotify.com/v1/me/tracks', headers=headers)
print(response.text)
I get this error:
{
"error" : {
"status" : 401,
"message" : "Missing token"
}
}
But If I go in the Spotify API console and get manually a token and put it manually after bearer, then it works, obviously I'm trying to automate the process so I can't take it by hand every time. If I print the token it's actually a token(I mean it's not None or similar), but it's like if It is the wrong one.
How can I fix this problem?
This error message is stupid. What it should tell you is that your authorization token does not have the grant to access the user.
There's 2 different ways to authorize:
client credentials (as you do, can't access any user related stuff)
Authorization Code Flow, see: https://developer.spotify.com/documentation/general/guides/authorization/code-flow/
The second way requires a bit more setup in your app. Basically get redirected to spotify webpage, then the user selects allow for the required permissions, then you get back a code and with that you can get a token and the refresh token (this one is the interesting part).
Now this is quite a hustle to get through, but once you have the refresh token you can basically do almost the same call you do just to get a refreshed access token. (See "Request a refreshed Access Token" at the bottom of the page I linked above)
So with refresh token you can do:
POST https://accounts.spotify.com/api/token
HEADER:
Authorization: Basic $base64(clientId:clientSecret)
BODY Parameters (form url encoded)
grant_type: refresh_token
refresh_token: <your value here>
Use this improved access token and it will work.

microsoft graph cant get refresh token using refresh token

The first time I was able to get both access token and refresh token,
Then when I use the refresh token to refresh it only gave me back access token and doesn't give me back the refresh token too, I want to get both the refresh token and access token,
request_url = "https://login.microsoftonline.com/common/oauth2/v2.0/token"
headers = {"Content-Type": "application/x-www-form-urlencoded"}
scope_list = ["https://graph.microsoft.com/Calendars.ReadWrite"]
scope = "%20".join(scope_list)
# redirect_uri = f"{settings.FRONTEND_BASE_URL}/microsoft/login"
redirect_uri = (
f"https://someuri.com/login"
)
refresh_token = user.profile.calendar_settings.outlook_refresh_token
payload = {
"client_id": "",
"scope": scope,
"redirect_uri": redirect_uri,
"client_secret": "",
"grant_type": "refresh_token",
"refresh_token": refresh_token,
}
response = requests.post(url=request_url, headers=headers, data=payload)
I got it working by changing the scope to this
scope = "https://graph.microsoft.com/Calendars.ReadWrite offline_access"
Please ensure your call includes following parameters in payload
grant_type:refresh_token
client_id:"your_client_id_comes_here"
client_secret:"your_client_secret_comes_here"
response_type:token
refresh_token:"old_refres_token_comes_here"
For more details please refer below screenshot
Postman request to get new access token with refresh token

Making a request to Dynamics CRM Web API

I'm trying to make an app that makes requests to Dynamics CRM Web API from python using urllib2.
So far I can login an user with an Azure application by making a post request to https://login.microsoftonline.com/common/oauth2/authorize
then with the retrieved authorization_code I can get the access_token, refresh_token and others with urllib2
url = 'https://login.microsoftonline.com/common/oauth2/token'
post_fields = {'grant_type': 'authorization_code',
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'redirect_uri': REDIRECT_URI,
'resource': 'https://graph.microsoft.com',
'code': code}
request = Request(url, urlencode(post_fields).encode())
resp = urlopen(request).read().decode()
resp = json.loads(resp)
refresh_token = resp['refresh_token']
id_token = resp['id_token']
id_token = jwt.decode(id_token,verify=False)
access_token = resp['access_token']
Then I tried to make another post request by using the access_token but had no luck.
I keep getting:
HTTP Error 401: Unauthorized
Just as a test I make a post directly to .dynamics.com/api/data/v8.1/leads
as follows:
url = 'https://<company_uri>.dynamics.com/api/data/v8.1/leads'
post_fields = {"name": "Sample Account",
"creditonhold": "false",
"address1_latitude": 47.639583,
"description": "This is the description of the sample account",
"revenue": 5000000,
"accountcategorycode": 1
}
request = Request(url, urlencode(post_fields).encode())
request.add_header('Authorization', 'Bearer ' + access_token )
request.add_header("Content-Type", "application/json; charset=utf-8")
request.add_header('OData-MaxVersion','4.0')
request.add_header('OData-Version','4.0')
request.add_header('Accept','application/json')
resp = urlopen(request).read().decode()
But i keep getting the same 401 error code.
I've looked all over msdn documentation but didn't find the way to do this directly without using any library, I just want to use a simple post request.
Since the error code says Unauthorized I think the access_token must be sent in some other way.
Can someone help me on how to correctly use the access_token on Dynamics CRM?
Thanks!
The access token you got back is for the Azure AD Graph API. Not Dynamics CRM.
To call that, you must ask for an access token with resource set to Dynamics CRM API's App ID URI, not https://graph.windows.net.
According to documentation you should set resource to https://<company_uri>.crm.dynamics.com.
So when you are retrieving token:
url = 'https://login.microsoftonline.com/common/oauth2/token'
post_fields = {'grant_type': 'authorization_code',
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'redirect_uri': REDIRECT_URI,
'resource': 'https://<company_uri>.crm.dynamics.com',
'code': code}

Azure Access Token Request returning HTML

I am trying to request an authorization code as documented here.
I am using Python requests package to do this and have the following example code:
import requests
auth_endpoint = 'https://login.microsoftonline.com/%s/oauth2/authorize?api-version=1.0' % TENANT_ID
payload = {
'client_id': CLIENT_ID,
'response_type': 'code',
'resource': APP_ID_URI,
'redirect_uri': REPLY_URL
}
response = requests.get(url=auth_endpoint, data=payload)
However, when I run the code above, I get back HTML in the body and not the response I'm expecting. It seems like the HTML code is for a login page.
When I take the formatted endpoint URI and plug it into a browser, I am able to get the auth code from the redirect URI. But, is there a way to get this from the body of the response while still using the requests package?
Please use session class of requests module to implement your requirement. Please refer to the following code sample:
import requests
s = requests.Session()
USERNAME = '<username_email>'
PASSWORD = '<userpassword>'
s.auth = (USERNAME, PASSWORD)
TENANT_ID = '<tenant_id>'
# Authorize URL
authorize_url = 'https://login.microsoftonline.com/%s/oauth2/authorize' % TENANT_ID
# Token endpoint.
token_url = 'https://login.microsoftonline.com/%s/oauth2/token' % TENANT_ID
payload = { 'response_type': 'code',
'client_id': '<tenant_id>',
'redirect_uri': 'http://localhost',
'authority' :'authority'
}
response = s.get(authorize_url, params=payload ,allow_redirects=True)
print response
print response.url
Any further concern, please feel free to let me know.

Categories

Resources