DeviceCheck: Unable to verify authorization token - python

I’m trying to get DeviceCheck to work, where I keep getting this response from Apple’s server: 401 Unable to verify authorization token.
The device_token is being sent to my python server over a base64 encoded string in JSON payload. Any ideas what I might be doing wrong?
Here is my code example:
def device_check_query(device_token):
data = {
'device_token': device_token,
'transaction_id': str(uuid4()),
'timestamp': int(time.time() * 1000),
}
jw_token = get_jw_token()
headers = {'Authorization': 'Bearer ' + jw_token}
response = requests.post(QUERY_URL, json=data, headers=headers)
return response.content
def get_jw_token():
with open(KEY_FILE, 'r') as cert_file:
certificate = cert_file.read()
jw_token = jwt.encode(
{'iss': TEAM_ID}, certificate,
algorithm='ES256',
headers={'kid': KEY_ID})
return jw_token

you need to add in the payload the issuer key and iat then it will work, check my code below
import time
def device_check_query(device_token):
data = {
'device_token': device_token,
'transaction_id': str(uuid.uuid4()),
'timestamp': int(time.time() * 1000),
}
jw_token = get_jw_token()
headers = {'Authorization': 'Bearer ' + jw_token}
response = requests.post(url, json=data, headers=headers)
return response.content
def get_jw_token():
with open('myfile.p8', 'r') as cert_file:
certificate = cert_file.read()
jw_token = jwt.encode(
{'iss': issuer,'iat': int(time.time())}, certificate,
algorithm='ES256',
headers={'kid': keyid})
return jw_token
device_check_query(u"1234e323a22133....")

Related

How to get user details after login via oauth?

Trying to understand how it works oauth
How to get authorized user details using Blizzard api?
import json
import requests
client_id = ""
client_secret = ""
region = "eu"
data = {
'grant_type': 'client_credentials'
}
access_token_response = requests.post(f"https://{region}.battle.net/oauth/token", data=data, allow_redirects=False, auth=(client_id, client_secret))
access_token = json.loads(access_token_response.text)["access_token"]
api_call_headers = {
'Authorization': 'Bearer ' + access_token
}
api_call_response = requests.get(f"https://{region}.battle.net/oauth/userinfo", headers=api_call_headers)

Cloud function require authentication error

I want to trigger the cloud functions with a self-signed JWT for a Google-signed ID token. However, it produces the response Your client does not have permission to the requested URL. I am sure that that account has "Cloud Functions Invoker" access and I also get the token successfully.
import time
import jwt
import json
# import http.client
# payload
private_key = "\n-----END PRIVATE KEY-----\n"
token_dict = {
"iss": "het-query-function#smarter-poc.iam.gserviceaccount.com",
"scope": "https://www.googleapis.com/auth/cloud-platform",
"aud": "https://www.googleapis.com/oauth2/v4/token",
# "aud": "https://europe-central2-smarter-poc.cloudfunctions.net/query_soc_ota_information",
"exp": time.time()+3600,
'iat': time.time(), # 时间戳
"sub":"het-query-function#smarter-poc.iam.gserviceaccount.com"
}
"""payload 中一些固定参数名称的意义, 同时可以在payload中自定义参数"""
# iss 【issuer】发布者的url地址
# sub 【subject】该JWT所面向的用户,用于处理特定应用,不是常用的字段
# aud 【audience】接受者的url地址
# exp 【expiration】 该jwt销毁的时间;unix时间戳
# nbf 【not before】 该jwt的使用时间不能早于该时间;unix时间戳
# iat 【issued at】 该jwt的发布时间;unix 时间戳
# jti 【JWT ID】 该jwt的唯一ID编号
# headers
headers = {
'alg': "RS256", # 声明所使用的算法
'typ': 'JWT'
}
# 调用jwt库,生成json web token
jwt_token = jwt.encode(token_dict, # payload, 有效载体
private_key, # 进行加密签名的密钥
algorithm="RS256", # 指明签名算法方式, 默认也是HS256
headers=headers # json web token 数据结构包含两部分, payload(有效载体), headers(标头)
).decode('ascii') # python3 编码后得到 bytes, 再进行解码(指明解码的格式), 得到一个str
print(jwt_token)
import http.client
conn = http.client.HTTPSConnection("www.googleapis.com")
# payload = 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjllN2Q5ZTk1YjZkNTdiY2NiZjBhYmM2NzgzYzc2N2RhYjE2MzFjOWIiLCJ0eXAiOiJKV1QifQ.eyJpYXQiOjE2NDMwMDUwMzAsImV4cCI6MTY0MzAwNTYzMCwic3ViIjoiZ2NwLXN0b3JhZ2VAc21hcnRlci1wb2MuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJpc3MiOiJnY3Atc3RvcmFnZUBzbWFydGVyLXBvYy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImF1ZCI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL29hdXRoMi92NC90b2tlbiIsInNjb3BlIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vYXV0aC9jbG91ZC1wbGF0Zm9ybSJ9.eAgCd5JbliFLoggcE9z7Ybhrd0GO3vb3zBW9N48iDe9tGBkQKaFdgAeANutoYLmLuvQM4m4NSavIKFHWYJHiZ6-ioehUvrs0qHZFe2bBkbNYAMQTW73ERr1XjufnZkgK6u1TUTpcX9u2EiJyMHIuku4PBYlhv8aniIsYojVfA_wVcmKhN0dVeBQzixZ_mhJsIZRPKYDPkJKn4H4oOXgy_ymbvKmguZyYLuPGezgycZpKwhFOvQQTbVSuoKikow9v4JIISXlt0fuspFLlsaEVWRx4468GUJ1SNyYThkXARRFxQAWMsgAJ2Z25I38Z3i-owWDnFKJl8KrtjSGG52sa8w'
payload = 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion='+jwt_token
headers = {
'Authorization': 'Bearer '+jwt_token,
'Content-Type': 'application/x-www-form-urlencoded'
}
conn.request("POST", "/oauth2/v4/token", payload, headers)
res = conn.getresponse()
data = res.read()
jwt = data.decode("utf-8")
print(jwt)
jwt_list = json.loads(jwt)
print(jwt_list['access_token'])
for v in range(len(jwt_list['access_token'])-1,-1,-1):
# print(jwt_list['access_token'][v])
if jwt_list['access_token'][v]!='.':
break
print(jwt_list['access_token'][v])
print("!!!!!!!")
jwt_str = jwt_list['access_token'][0:v+1]
print(jwt_str)
conn = http.client.HTTPSConnection("europe-central2-smarter-poc.cloudfunctions.net")
headers = {
'Authorization': 'bearer '+jwt_str
}
payload = ""
conn.request("GET", "/query_soc_ota_information/?hello=hello", payload, headers)
res = conn.getresponse()
data = res.read()
re = data.decode("utf-8")
print(re)
OK, your code works for me but with several changes.
It would be helpful to include which JWT you're library; I assume PyJWT
You need to include target_audience
ALG="RS256"
PROJECT=os.getenv("PROJECT")
REGION=os.getenv("REGION")
ACCOUNT=os.getenv("ACCOUNT")
FUNCTION=os.getenv("FUNCTION")
EMAIL="{account}#{project}.iam.gserviceaccount.com".format(
account=ACCOUNT,
project=PROJECT,
)
ROOT="{region}-{project}.cloudfunctions.net".format(
region=REGION,
project=PROJECT,
)
ENDPOINT="https://{root}/{function}".format(
root=ROOT,
function=FUNCTION,
)
token_dict = {
"target_audience": ENDPOINT,
"iss": EMAIL,
"sub": EMAIL,
"exp": time.time()+3600,
"iat": time.time(),
"aud": "https://www.googleapis.com/oauth2/v4/token",
}
NOTE I think exp and iat should be integers but your code works as-is.
The .decode("ascii") appended to jwt.encode().decode("ascii") is incorrect.
The payload should not be URL-encoded:
payload = "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion={jwt}".format(
jwt=jwt_token,
)
The /oauth2/v4/token endpoint does not return an access_token per #john-hanley comment. It returns an id_token (as described by Google in the doc you reference).
jwt = data.decode("utf-8")
jwt_list = json.loads(jwt)
id_token=jwt_list["id_token"]
conn = http.client.HTTPSConnection(ROOT)
headers = {
"Authorization": "Bearer {token}".format(token=id_token),
}
conn.request("GET", "/{function}".format(function=FUNCTION), headers=headers)
NOTE No payload (null) not ""
main.py:
import http.client
import json
import jwt
import os
import time
ALG="RS256"
# Use GOOGLE_APPLICATION_CREDENTIALS for consistency
CREDENTIALS=os.getenv("GOOGLE_APPLICATION_CREDENTIALS")
f=open(CREDENTIALS)
key=json.load(f)
PRIVATE_KEY=key["private_key"]
PROJECT=os.getenv("PROJECT")
REGION=os.getenv("REGION")
ACCOUNT=os.getenv("ACCOUNT")
FUNCTION=os.getenv("FUNCTION")
EMAIL="{account}#{project}.iam.gserviceaccount.com".format(
account=ACCOUNT,
project=PROJECT,
)
ROOT="{region}-{project}.cloudfunctions.net".format(
region=REGION,
project=PROJECT,
)
ENDPOINT="https://{root}/{function}".format(
root=ROOT,
function=FUNCTION,
)
token_dict = {
"target_audience": ENDPOINT,
"iss": EMAIL,
"sub": EMAIL,
"exp": time.time()+3600,
"iat": time.time(),
"aud": "https://www.googleapis.com/oauth2/v4/token",
}
headers = {
'alg': ALG,
'typ': 'JWT'
}
jwt_token = jwt.encode(
token_dict,
PRIVATE_KEY,
algorithm=ALG,
headers=headers,
)
payload = "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion={jwt}".format(
jwt=jwt_token,
)
headers = {
"Authorization": "Bearer {token}".format(
token=jwt_token,
),
"Content-Type": 'application/x-www-form-urlencoded'
}
conn = http.client.HTTPSConnection("www.googleapis.com")
conn.request("POST", "/oauth2/v4/token", payload, headers)
res = conn.getresponse()
data = res.read()
jwt = data.decode("utf-8")
jwt_list = json.loads(jwt)
id_token=jwt_list["id_token"]
conn = http.client.HTTPSConnection(ROOT)
headers = {
"Authorization": "Bearer {token}".format(token=id_token),
}
conn.request("GET", "/{function}".format(function=FUNCTION), headers=headers)
res = conn.getresponse()
data = res.read()
re = data.decode("utf-8")
print(re)

how do I connect with salesforce with python requests?

Traceback error while connecting with salesforce API: [{'message': 'INVALID_HEADER_TYPE', 'errorCode': 'INVALID_AUTH_HEADER'}]
What is the problem?
My python codes are as follows:
client_id = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
client_secret = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
redirect_url = 'http://localhost/'
cm_user = 'XXXXXXXXXXXXXXXXXXXXXX'
cm_pass = 'XXXXXXXXXXXXXXXXXXXXXX'
auth_url = 'https://login.salesforce.com/services/oauth2/token'
response = requests.post(auth_url, data = {
'client_id': client_id,
'client_secret': client_secret,
'grant_type':'password',
'username': cm_user,
'password': cm_pass
})
json_res = response.json()
access_token = json_res['access_token']
auth = {'Authorization': 'Bearer' + access_token}
instance_url = json_res['instance_url']
url = instance_url + '/services/data/v45.0/sobjects/contact/describe'
res = requests.get(url, headers=auth)
r = res.json()
print(r)
You are missing a space after the word Bearer, which renders your authorization header invalid.

Trying to retrieve data from the Anbima API

I'm trying to automate a process in which i have to download some brazilian fund quotes from Anbima (Brazil regulator). I have been able to work around the first steps to retrieve the access token but i don't know how to use the token in order to make requests. Here is the tutorial website https://developers.anbima.com.br/en/como-acessar-nossas-apis/.
I have tried a lot of thing but all i get from the request is 'Could not find a required APP in the request, identified by HEADER client_id.'
If someone could share some light. Thank you in advance.
import requests
import base64
import json
requests.get("https://api.anbima.com.br/feed/fundos/v1/fundos")
ClientID = '2Xy1ey11****'
ClientSecret = 'faStF1Hc****'
codeString = ClientID + ":" + ClientSecret
codeStringBytes = codeString.encode('ascii')
base64CodeBytes = base64.b64encode(codeStringBytes)
base64CodeString = base64CodeBytes.decode('ascii')
url = "https://api.anbima.com.br/oauth/access-token"
headers = {
'content-type': 'application/json'
,'authorization': f'Basic {base64CodeString}'
}
body = {
"grant_type": "client_credentials"
}
r = requests.post(url=url, data=json.dumps(body), headers=headers, allow_redirects=True)
jsonDict = r.json()
##################
urlFundos = "https://api-sandbox.anbima.com.br/feed/precos-indices/v1/titulos-publicos/mercado-secundario-TPF"
token = jsonDict['access_token']
headers2 = {
'content-type': 'application/json'
,'authorization': f'Bearer {token}'
}
r2 = requests.get(url=urlFundos, headers=headers2)
r2.status_code
r2.text
I was having the same problem, but today I could advance. I believe you need to adjust some parameters in the header.
Follows the piece of code I developed.
from bs4 import BeautifulSoup
import requests
PRODUCTION_URL = 'https://api.anbima.com.br'
SANDBOX_URL = 'https://api-sandbox.anbima.com.br'
API_URL = '/feed/fundos/v1/fundos/'
CODIGO_FUNDO = '594733'
PRODUCTION = False
if PRODUCTION:
URL = PRODUCTION_URL
else:
URL = SANDBOX_URL
URL = URL + API_URL + CODIGO_FUNDO
HEADER = {'access_token': 'your token',
'client_id' : 'your client ID'}
html = requests.get(URL, headers=HEADER).content
soup = BeautifulSoup(html, 'html.parser')
print(soup.prettify())
The sandbox API will return a dummy JSON. To access the production API you will need to request access (I'm trying to do this just now).
url = 'https://api.anbima.com.br/oauth/access-token'
http = 'https://api-sandbox.anbima.com.br/feed/precos-indices/v1/titulos-publicos/pu-intradiario'
client_id = "oLRa*******"
client_secret = "6U2nefG*****"
client_credentials = "oLRa*******:6U2nefG*****"
client_credentials = client_credentials.encode('ascii')
senhabytes = base64.b64encode(client_credentials)
senha = base64.b64decode(senhabytes)
print(senhabytes, senha)
body = {
"grant_type": "client_credentials"
}
headers = {
'content-type': 'application/json',
'Authorization': 'Basic b0xSYTJFSUlOMWR*********************'
}
request = requests.post(url, headers=headers, json=body, allow_redirects=True)
informacoes = request.json()
token = informacoes['access_token']
headers2 = {
"content-type": "application/json",
"client_id": f"{client_id}",
"access_token": f"{token}"
}
titulos = requests.get(http, headers=headers2)
titulos = fundos.json()
I used your code as a model, then I've made some changes. I've printed the encode client_id:client_secret and then I've copied and pasted in the headers.
I've changed the data for json.

converting python oauth to postman request

I am trying to convert successful python (flask) OAuth 2.0 authentication / api request into Postman.
My current process is:
From the front end, I hit an /auth endpoint in python using fetch:
fetch("/auth")
.then(function (response) {
return response.json();
})
.then(function (json) {
const code = json.code;
window.location = `[hostname.com]/auth/authorize?request_token=${code}&redirect_uri=http://[hostname]/menu`;
});
The backend flask auth endpoint looks like this:
url = 'https://[hostname].com/v3/oauth/request'
headers = CaseInsensitiveDict()
headers['Host'] = '[hostname].com'
headers['Content-Type'] = 'application/json'
headers['X-Accept'] = 'application/json'
data = json.dumps({'consumer_key': 'XXXX', 'redirect_uri':'[hostname]/success'})
resp = requests.post(url, headers=headers, data=data)
json_resp = json.loads(resp.content)
auth_code = json_resp['code']
auth_resp = {'code': auth_code}
return jsonify(auth_resp)
The access endpoint takes that auth code to get the token
cur_auth = session.get('auth_code',None)
url = 'https://[hostname.com]/v3/oauth/authorize'
headers = CaseInsensitiveDict()
headers['Host'] = '[hostname].com'
headers['Content-Type'] = 'application/json; charset=UTF-8'
headers['X-Accept'] = 'application/json'
data = json.dumps({'consumer_key': 'XXXX', 'code': cur_auth})
resp = requests.post(url, headers=headers, data=data)
json_resp = resp.json()
access_token = json_resp['access_token']
username = json_resp['username']
session['access_token']=access_token
session['username']=username
access_resp = {'access': access_token, 'user': username}
return jsonify(access_resp)
But when I try to translate this into a postman request, I can't really understand where some of the things like the consumer_key request_token and code get defined.
I'm currently getting a 400 bad request with this setup:
where the consumer_key is in Postman's client secret field, and where
https://[hostname].com/v3/oauth/request is in Postman's auth field and
https://getpocket.com/v3/oauth/authorize is in Postman's access token url field.

Categories

Resources