Request authorization in flask - python

I am developing a Flask application which gives call to the REST service developed in Flask. The target REST service method is secured using Basic Authentication. I found that for this type of authentication, I have to use base64 encoding.
I am trying to pass the credentials to the service in this way:
headers = {'username': base64.b64encode(g.user['username'])}
response = requests.post('http://127.0.0.1:3000/api/v1.0/follower/' + username, headers=headers)
And at the service side, the username is fetched as :
user_name = request.authorization.username
However, the service is not able to authorize the provided credentials and it is throwing an error 401.
Is there any issue with the authorization at the service side and at the application side?

You are not creating a proper Basic Authorization header.
You'd have to call the header Authorization, and then set the header value to the string Basic <base64-of-username-and-password-separated-by-a-colon>.
If we assume an empty password, that would look like:
headers = {
'Authorization': 'Basic {}'.format(
base64.b64encode(
'{username}:{password}'.format(
username=g.user['username'],
password='')
)
),
}
See the Wikipedia description of the client side of the protocol.
However, there is no need to construct this manually, as requests will create the header for you when you pass in a username and password as a tuple to the auth keyword:
response = requests.post(
'http://127.0.0.1:3000/api/v1.0/follower/' + username,
auth=(g.user['username'], ''))

for me the working code was, but may have some error.
headers = {
'Authorization': 'Basic {}'.format(
base64.b64encode(
'{username}:{password}'.format(
username=g.user['username'],
password='').encode()
).decode()
)
}

Related

How to get Microsoft Graph API token to read mails

I'm trying to retrieve mails from my organization's mailbox, and I can do that via Graph Explorer. However, when I use the same information that I used in Graph Explorer, the generated token returns an error stating '/me request is only valid with delegated authentication flow.' in me/messages endpoint.
So, how can I generate the acceptable token for the /me endpoint?
An example python code or example Postman request would be amazing.
It sounds like the endpoint you're using in Graph Explorer is something like this
https://graph.microsoft.com/v1.0/me/messages
/me is referring to the user signed into Graph Explorer. If you want to read another user's messages you would use
https://graph.microsoft.com/v1.0/users/user#domain.com/messages
When connecting to Graph API as an application with no user interaction, you can never use /me endpoints, as there's no user logged in.
Reference
https://learn.microsoft.com/en-us/graph/api/user-list-messages?view=graph-rest-1.0
Python example to list messages
import requests
def get_messages(access_token, user):
request_url = f"https://graph.microsoft.com/v1.0/users/{user}/messages"
request_headers = {
"Authorization": "Bearer " + access_token
}
result = requests.get(url = request_url, headers = request_headers)
return(result)
msgs = get_messages(access_token = token['access_token'], user = "userPrincipalName#domain.com")
print(msgs.content)
Additional example of obtaining a token, using an app registration and client secret
import msal
def get_token_with_client_secret(client_id, client_secret, tenant_id):
# This function is to obtain a bearer token using the client credentials flow, with a client secret instead of a certificate
# https://docs.microsoft.com/en-us/graph/sdks/choose-authentication-providers?tabs=CS#client-credentials-provider
app = msal.ConfidentialClientApplication(
client_id = client_id,
client_credential = client_secret,
authority = f"https://login.microsoftonline.com/{tenant_id}")
scopes = ["https://graph.microsoft.com/.default"]
token = app.acquire_token_for_client(scopes = scopes)
return(token)

Python (requests library) ETL: Spotify API "Authorization Code Flow" - Request Access Token Problem

Context:
I'm working on a side project to pull data from the Spotify API into a
Microsoft SQL Server database as part of a refreshing ETL job. I need
to use the "Authorization Code Flow" so I can authorize/authenticate
programmatically, so my table will populate each day.
I'm using the Python requests library for this, and I don't want to
make an Object Oriented Solution for this if possible (not my
preference).
Problem:
I'm having trouble getting the Access Token after authenticating.
Looking at similar issues, it's very similar to this one:
Spotify API Authorization Code Flow with Python
.
I'm not sure why I'm getting a Response 400 (Bad Request) from this.
Can someone please advise here?
Code:
# used to to encode byte string from CLIENT_ID : CLIENT_SECRET, then decode for Authentication Header
import base64
# used to make HTTP requests from Spotify API
import requests
# used to access the environment variables
import os
def request_user_authorization():
'''
HTTP GET request to gain access to data (Authorization Code Flow)
HTTP POST request to send the code and receive an Authorization Token (current issue)
https://developer.spotify.com/documentation/general/guides/authorization/code-flow/
'''
# URLs
AUTH_URL = 'https://accounts.spotify.com/authorize'
TOKEN_URL = 'https://accounts.spotify.com/api/token'
BASE_URL = 'https://api.spotify.com/v1'
SPOTIFY_URI = 'https://api.spotify.com/v1/me/player/recently-played'
# sensitive items
CLIENT_ID = os.environ.get('SPOTIFY_CLIENT_ID_ENV')
CLIENT_SECRET = os.environ.get('SPOTIFY_CLIENT_SECRET_ENV')
# make a request to the /authorize endpoint to get an authorization code
user_authorization_code = requests.get(
AUTH_URL, {
'client_id': CLIENT_ID,
'response_type': 'code',
'redirect_uri': SPOTIFY_URI,
'scope': 'user-read-recently-played',
}
)
# Code 200 = "OK"
print(user_authorization_code)
#----------------------------------------------------------#
api_header_string = base64.urlsafe_b64encode((CLIENT_ID + ':' + CLIENT_SECRET).encode('ascii'))
api_headers={
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic %s' % api_header_string.decode('ascii')
}
api_payload = {
'grant_type': 'authorization_code',
'code': user_authorization_code,
'redirect_uri': SPOTIFY_URI,
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET
}
#issue here:
# Make a request to the /token endpoint to get an access token
access_token_request = requests.post(url=TOKEN_URL, data=api_payload, headers=api_headers)
# returns <Response [400]>
# https://datatracker.ietf.org/doc/draft-ietf-httpbis-semantics/
# 15.5.1. 400 Bad Request
# The _400 (Bad Request)_ status code indicates that the server cannot
# or will not process the request due to something that is perceived to
# be a client error (e.g., malformed request syntax, invalid request
# message framing, or deceptive request routing).
# print(access_token_request)
#----------------------------------------------------------#
request_user_authorization()
You seem to have misunderstood how the Authorizatuon Code Flow works.
The redirect_uri in this kind of flow is used by the provider api (here spotify) as a callback to give you the authorization code.
The spotify API will call this url with a code parameter that you can use to ask for a token.
Meaning that for this flow to work you need a web server ready to receive requests on the uri that you have given in your code request (and specified when creating your app on the spotify developer portal). You might be better off using the Client Credentials Flow for your use case.
Also you should always use the name of the keywords arguments when using requests.get, requests.post ... It makes the code clearer and the order of the arguments differ for each method so it can get confusing if you don't.
#Speedlulu you're correct, that was the problem.
For anyone in the future reading this question: this is what I learned since posting the question:
What I misunderstood was the flow of data, and that Client Credentials Flow (Application to Spotify only) was the better choice because I don't need to have a "User" portion to this program.
Spotify's Client Credentials Flow Documentation: https://developer.spotify.com/documentation/general/guides/authorization/client-credentials/
# used to access environment variables securely (sensitive data)
import os
# used to encode strings into bytes and back
import base64
# used to convert JSON data into strings
import json
# endpoint that I'm connecting to on Spotify's servers
token_request_url = "https://accounts.spotify.com/api/token"
CLIENT_ID = os.environ.get('SPOTIFY_CLIENT_ID_ENV')
CLIENT_SECRET = os.environ.get('SPOTIFY_CLIENT_SECRET_ENV')
# encode credentials into bytes, then decode into a string for the HTTP POST request to Spotify to authenticate
BASE64_ENCODED_HEADER_STRING = base64.b64encode(bytes(f"{CLIENT_ID}:{CLIENT_SECRET}", "ISO-8859-1")).decode("ascii")
#initializing dictionaries for HTTP POST request
headers = {}
data = {}
headers['Authorization'] = f"Basic {BASE64_ENCODED_HEADER_STRING}"
data['grant_type'] = "client_credentials"
data['json'] = True
data['scope'] = 'user-read-recently-played'
r = requests.post(url=token_request_url, headers=headers, data=data)
# prints the response from the server regarding the access token data (formatted to be easier to read)
print(json.dumps(r.json(), indent=2))
# store the token value in a variable for HTTP GET request
token = r.json()['access_token']
What was unclear is that I first need to POST my request with the credentials to get the token (using the specific URL to do), store the r.json()['access_token'] value in a variable, then use that as part of the following GET request to access my specific data.

Why google email auto forwarding throw error when using access_token generated using code?

Currently Now I am developing code to forward emails onto another email_id.
My code is as below.
flow = flow_from_clientsecrets(settings.CLIENTSECRETS_LOCATION, ' '.join(settings.SCOPES))
flow.redirect_uri = settings.REDIRECT_URI
credentials = flow.step2_exchange(authorization_code)
url = 'https://www.googleapis.com/gmail/v1/users/moon#mydomain.com/settings/forwardingAddresses'
body = {
"forwardingEmail": "test#mydomain.com",
}
headers = {'Authorization': 'Bearer ' + credentials.access_token}
api_call_response = requests.post(url, headers=headers, json=body)
I have used below scopes
SCOPES = [
'https://www.googleapis.com/auth/gmail.readonly',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/gmail.settings.sharing',
'https://mail.google.com/',
]
I am getting below error:
Access restricted to service accounts that have been delegated domain-wide authority
But when I am doing same with postman where I am generating access token using Get New Access Token button api works perfectly.
Postman SS access token:
My question is when generating access token from postman It works properly but with code it generating access restriction error.
Thanks.

How to connect Microsoft Graph using python without UI Interaction?

I'm following this link> python-sample-send-mail to send email, but I would like to skip or authenticate the user on background without any UI interaction. I don't like the idea that OAuth: pop up a window.
My application is registered in Microsoft Azure AD.
I would like to know how to authenticate with a Email username and a password without UI interaction.
Thanks a lot!
Based on the doc:AAD V2.0 end pointRestrictions on protocols ,The OAuth 2.0 Resource Owner Password Credentials Grant is not supported by the v2.0 endpoint.
In python ADAL sdk , client secret is not accepted by acquire_token_with_username_password method, so you need to register native app.
Sample code:
import adal
import requests
tenant = ""
client_id = "app id"
# client_secret = ""
username = ""
password = "”
authority = "https://login.microsoftonline.com/" + tenant
RESOURCE = "https://graph.microsoft.com"
context = adal.AuthenticationContext(authority)
# Use this for Client Credentials
#token = context.acquire_token_with_client_credentials(
# RESOURCE,
# client_id,
# client_secret
# )
# Use this for Resource Owner Password Credentials (ROPC)
token = context.acquire_token_with_username_password(RESOURCE, username, password, client_id)
graph_api_endpoint = 'https://graph.microsoft.com/v1.0{0}'
# /me only works with ROPC, for Client Credentials you'll need /<UsersObjectId/
request_url = graph_api_endpoint.format('/me')
headers = {
'User-Agent' : 'python_test',
'Authorization' : 'Bearer {0}'.format(token["accessToken"]),
'Accept' : 'application/json',
'Content-Type' : 'application/json'
}
response = requests.get(url = request_url, headers = headers)
print (response.content)
In addition, native app is not necessary if you use REST API, but client secret need to be set.
Hope it helps you.

Spotify "Unexpected status: 400" when refreshing and accessing token - python

When trying to authorize spotify using python 3, I get a "server_error" with the description "Unexpected status: 400".
I am using the correct authorization code and the spotify documentation (https://developer.spotify.com/web-api/authorization-guide/) instructed me to use a post command with those parameters.
I'm quite a noob in this and I do not know what I am doing wrong.
Here is the code:
import requests
params = {'grant_type': 'authorization_code', 'code': authcode, 'redirect_uri': 'https://example.com/callback','client_id':'example', 'client_secret':'example'}
req=requests.post('https://accounts.spotify.com/api/token', params=params)
print(req.content)
According to spotify's own guide (see step #4):
https://developer.spotify.com/web-api/authorization-guide/
The authorization info for requesting a new token must go in the header via an "Authorization" variable:
Authorization: Required. Base 64 encoded string that contains the
client ID and client secret key. The field must have the format:
Authorization: Basic base64 encoded client_id:client_secret
You have it instead in the request body itself.
So you should do something like:
import requests
import base64
authcode = 'valid_authcode_from_prev_authorization_step'
params = {'grant_type': 'authorization_code', 'code': authcode, 'redirect_uri': 'https://example.com/callback'}
client_id = 'example_id'
client_secret = 'example_secret'
b64_val = base64.b64encode("%s:%s" % (client_id, client_secret))
req = requests.post(
'https://accounts.spotify.com/api/token', params=params,
headers={'Authorization': b64_val})
However, for this to work you need a valid auth code which you can only get by having the user go through the auth step which precedes the token acquisition step.
This code gets sent to the callback you have registered in your app settings, which won't work if you have a fake callback set (ie: http://example.com/callback).

Categories