Can't grant permissions for MS Asure graph API client app to fetch data about ManagedDevices. How to overcome? - authentication

I have registered a new app, copied tenant, client_id, and client_secret. I can access https://graph.microsoft.com/v1.0 with Bearer, and access token - works fine. But I can't get anything else. Tried to grant scopes to this app - w/o luck.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import pprint
import adal
import requests
pp = pprint.PrettyPrinter(indent=4).pprint
tenant = "<>"
client_id = "<>"
client_secret = "<>"
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
)
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('/Management/managedDevices')
#request_url = graph_api_endpoint.format('/me')
headers = {
'User-Agent' : 'python_tutorial/1.0',
'Authorization' : 'Bearer {0}'.format(token["accessToken"]),
'Accept' : 'application/json',
'Content-Type' : 'application/json'
}
response = requests.get(url = request_url, headers = headers)
pp(response.json())
Here is the error from HTTP reply from the API
{ 'error': { 'code': 'UnknownError',
'innerError': { 'date': '2020-03-15T06:57:54',
'request-id': 'f011ca02-f8c6-4bcb-90a2-9decbed2cfce'},
'message': '{"ErrorCode":"Unauthorized","Message":"{\\r\\n '
'\\"_version\\": 3,\\r\\n \\"Message\\": \\"An '
'error has occurred - Operation ID (for customer '
'support): 00000000-0000-0000-0000-000000000000 - '
'Activity ID: f011ca02-f8c6-4bcb-90a2-9decbed2cfce '
'- Url: '
'https://fef.amsua0402.manage.microsoft.com/DeviceFE/StatelessDeviceFEService/deviceManagement/managedDevices?api-version=2018-05-24\\",\\r\\n '
'\\"CustomApiErrorPhrase\\": \\"\\",\\r\\n '
'\\"RetryAfter\\": null,\\r\\n '
'\\"ErrorSourceService\\": \\"\\",\\r\\n '
'\\"HttpHeaders\\": '
'\\"{\\\\\\"WWW-Authenticate\\\\\\":\\\\\\"Bearer '
'realm=\\\\\\\\\\\\\\"urn:intune:service,c3998d6e-2e37-4c56-87b5-7b444ee1cb26,f0f3c450-59bf-4f0d-b1b2-0ef84ddfe3c7\\\\\\\\\\\\\\"\\\\\\"}\\"\\r\\n}","Target":null,"Details":null,"InnerError":null,"InstanceAnnotations":[]}'}}

You were using client credential flow which request an access token with application permissions.
However, managed device apis are not supported with application permissions.
Reference:
Delegated permissions and Application permissions

Related

Is it possible to convert HTTPBearer.credentials to Pydantic BaseModel in FastAPI?

I'm using FastAPI's HTTPBearer class to receive authorization tokens on request headers.
This is my dependencies file as per the FastAPI docs, which is used to retrieve the token on any request to the API.
classroom_auth_scheme = HTTPBearer(
scheme_name="Google Auth Credentials",
bearerFormat="Bearer",
description="O-Auth2 Credentials obtained on frontend, used to authenticate with Google services",
)
def get_classroom_token(
token: str = Depends(classroom_auth_scheme),
) -> requests.ClassroomAuthCredentials:
"""Converts a json string of Authorization Bearer token into ClassroomAuthCredentials class
Args:
token (str, optional): Autorization Header Bearer Token. Defaults to Depends(auth_scheme).
Raises:
HTTPException: 400 level response meaning the token was not in the correct format
Returns:
requests.ClassroomAuthCredentials
"""
try:
# token.credentials is a JSON String -> want: pydantic Basemodel
token_dict = json.loads(token.credentials)
token = requests.ClassroomAuthCredentials.parse_obj(token_dict)
return token
except Exception as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"{e}",
)
And this is how I receive the token in my routes:
#router.post("/test-auth", summary="Validate authentication with Google Classroom API")
async def test_auth(token=Depends(get_classroom_token)):
try:
gc_service_test = get_service(token)
gc_api_test = ClassroomApi(service=gc_service_test)
user_profile = gc_api_test.get_user_profile("me")
response: responses.ListGoogleClassroomCourses = {
"message": f"Auth Credentials Are Valid",
"userProfile": user_profile,
}
return JSONResponse(response)
except errors.HttpError as error:
# handle exceptions...
Is there a way to specify the data structure of token.credentials like there is for request body?
This would make it easier to access properties as well as provide a format in the authorize modal on the swagger docs for other developers on the team, so they don't have to guess what the required properties of the Authorization token are.
This is my data model of the token.credentials as a BaseModel
class ClassroomAuthCredentials(BaseModel):
token: str = Field(..., example="MyJWT")
clientId: str = Field(..., example="myClientId")
clientSecret: str = Field(..., example="myClientSecret")
refreshToken: str = Field(..., example="myRefreshToken")
scopes: list[str] = Field(
...,
example=[
"https://www.googleapis.com/auth/classroom.courses.readonly",
"https://www.googleapis.com/auth/classroom.coursework.students",
],
)

Need to access to the Bynder API

I am trying to connect to the Bynder API using Python and the documentation https://bynder.docs.apiary.io/ but I can make it to connect to the Analytics endpoint https://bynder.docs.apiary.io/#reference/analytics because I received a 401 response
I have the following code :
from bynder_sdk import BynderClient
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Origin': 'Allowed domain for cross-domain requests. Only required if any domains were specified in \'Set HTTP access control (CORS)\' for the OAuth application.',
'Authorization': 'Basic b64("abcd":"abcd")'
}
bynder_client = BynderClient(
domain='abcd.com',
redirect_uri='https://abcd.com/v7/analytics/api/v1/asset/view',
client_id='abcd',
client_secret='abcd',
scopes ="offline analytics.api:read",
grant_type="client_credentials"
)
print(bynder_client.get_authorization_url())
print(bynder_client.get_authorization_url()[1])
params = {"limit":"100", "fromDateTime":"2022-01-01T01:00","toDateTime":"2022-06-01T01:00" }
api_call_headers = {'Authorization': 'Token ' + bynder_client.get_authorization_url()[1]}
api_call_response = requests.get("https://abcd.abcd.com/v7/analytics/api/v1/asset/view", headers=api_call_headers, params=params, verify=False)
can someone help me to understand how to Autorise using OAuth 2.0 the Client ID and Client Secret and use the Analytics endpoint? I have all the details in the bynder_client = BynderClient()
Thanks
For anyone reference this his how I ended up making my code work:
endpoint_api_url="https://abcd.abcd.com/v7/analytics/api/v1/asset/download"
auth_server_url = "https://abcd.abcd.com/v6/authentication/oauth2/token"
client_id = 'abcd'
client_secret='abcd'
token_req_payload = {'grant_type': 'client_credentials'}
token_response = requests.post(auth_server_url,
data=token_req_payload, verify=False, allow_redirects=False,
auth=(client_id, client_secret))
print(token_response.status_code)
if token_response.status_code ==200:
print("Successfuly obtained a new token")
print(token_response.text)
tokens = json.loads(token_response.text)
token = tokens['access_token']
print(token)
else:
print("Failed to obtain token from the OAuth 2.0 server", file=sys.stderr)
sys.exit(1)
params = {"limit":"100", "fromDateTime":"2022-01-01T01:00","toDateTime":"2022-06-01T01:00" }
api_call_headers = {'Authorization': 'Bearer ' + token}
api_call_response = requests.get(endpoint_api_url, headers=api_call_headers, params=params, verify=False)
print(api_call_response.text)

Getting "unsupported_grant_type" when trying to refresh xero API token using python

Getting "unsupported_grant_type" when trying to refresh token using python
Hi,
I've been trying to get a new access token & refresh token using an existing refresh token that I have. I am following the documentation as stated on the website https://developer.xero.com/documentation/oauth2/auth-flow but I keep getting an error saying "unsupported_grant_type" although I do define grant_type = refresh_token. Here's my code, any help would be greatly appreciated.
import json
from base64 import b64encode
client_id = xxx
client_secret = xxx
RefreshToken = xxx
b64_id_secret = b64encode(client_id + ':' + client_secret)
def XeroRefreshToken(refresh_token):
token_refresh_url = 'https://identity.xero.com/connect/token'
response = requests.post(token_refresh_url,
headers = {
'Authorization' : 'Basic ' + b64_id_secret,
'Content-Type': 'application/x-www-form-urlencoded'
},
data = {
'grant_type' : 'refresh_token',
'refresh_token' : refresh_token
})
json_response = response.json()
print(json_response)
new_refresh_token = json_response['refresh_token']
XeroRefreshToken(RefreshToken)

Cannot POST request using service account key file in Python, getting 'Invalid IAP credentials: Unable to parse JWT', '401 Status Code'

I am trying to send a POST request to a Google App Engine service with a JSON body accompanied by an authorization token. I am generating the access token from a local service account key JSON file. The code below is generating a credential but finally the authorization is being rejected. I also tried different ways already. Even tried writing the request in Postman with a Bearer token in the Header, or even as a plain cURL command. But whatever I try, getting a 401 authentication error. I need to make sure whether the problem is in my side or on the other side with the service. Explored every documentation avaliable but no luck.
from google.auth.transport import requests
from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession
CREDENTIAL_SCOPES = ["https://www.googleapis.com/auth/cloud-platform"]
CREDENTIALS_KEY_PATH = 'my-local-service-account-key-file.json'
#the example service url I am trying to hit with requests
url = 'https://test.appspot.com/submit'
headers = {"Content-Type": "application/json"}
#example data I am sending with the request body
payload = {
"key1": "value 1",
"key2": "value 2"
}
credentials = service_account.Credentials.from_service_account_file(
CREDENTIALS_KEY_PATH,
scopes=CREDENTIAL_SCOPES
)
credentials.refresh(requests.Request())
authed_session = AuthorizedSession(credentials)
response = authed_session.request('POST',
url,
headers=headers,
data=payload
)
#adding some debug lines for your help
print(response.text)
print(response.status_code)
print(response.headers)
Getting the Output:
Invalid IAP credentials: Unable to parse JWT
401
{'X-Goog-IAP-Generated-Response': 'true', 'Date': 'Mon, 03 May 2021 06:52:11 GMT', 'Content-Type': 'text/html', 'Server': 'Google Frontend', 'Content-Length': '44', 'Alt-Svc': 'h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"'}
IAP expects a JWT(OpenID Connect (OIDC)) token in the Authorization header while your method will attach an access token the the Authorization header instead. Take a look at the below code snippet to make a request to an IAP secured resource.
Your code needs to be something like the following:
from google.auth.transport.requests import Request
from google.oauth2 import id_token
import requests
def make_iap_request(url, client_id, method='GET', **kwargs):
"""Makes a request to an application protected by Identity-Aware Proxy.
Args:
url: The Identity-Aware Proxy-protected URL to fetch.
client_id: The client ID used by Identity-Aware Proxy.
method: The request method to use
('GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE')
**kwargs: Any of the parameters defined for the request function:
https://github.com/requests/requests/blob/master/requests/api.py
If no timeout is provided, it is set to 90 by default.
Returns:
The page body, or raises an exception if the page couldn't be retrieved.
"""
# Set the default timeout, if missing
if 'timeout' not in kwargs:
kwargs['timeout'] = 90
# Obtain an OpenID Connect (OIDC) token from metadata server or using service
# account.
open_id_connect_token = id_token.fetch_id_token(Request(), client_id)
# Fetch the Identity-Aware Proxy-protected URL, including an
# Authorization header containing "Bearer " followed by a
# Google-issued OpenID Connect token for the service account.
resp = requests.request(
method, url,
headers={'Authorization': 'Bearer {}'.format(
open_id_connect_token)}, **kwargs)
if resp.status_code == 403:
raise Exception('Service account does not have permission to '
'access the IAP-protected application.')
elif resp.status_code != 200:
raise Exception(
'Bad response from application: {!r} / {!r} / {!r}'.format(
resp.status_code, resp.headers, resp.text))
else:
return resp.text
Note: The above method works with implicit credentials that can be set by running command: export GOOGLE_APPLICATION_CREDENTIALS=my-local-service-account-key-file.json to set the path to your service account in the environment and then run the python code from the same terminal.
Take a look at this link for more info.

How to get github token using username and password

I am developing mobile apps using rhodes. I want to access private repo of github. I am having only username and password.
How to get token of given username and password.
Once you have only login and password you can use them using basic auth. First of all, check if this code shows you json data of desired repo. Username and password must be separated by a colon.
curl -u "user:pwd" https://api.github.com/repos/user/repo
If succeeded you should consider doing this request from code.
import urllib2
import json
from StringIO import StringIO
import base64
username = "user#example.com"
password = "naked_password"
req = urllib2.Request("https://api.github.com/repos/user/repo")
req.add_header("Authorization", "Basic " + base64.urlsafe_b64encode("%s:%s" % (username, password)))
req.add_header("Content-Type", "application/json")
req.add_header("Accept", "application/json")
res = urllib2.urlopen(req)
data = res.read()
repository = json.load(StringIO(data))
You should use oauth instead: http://developer.github.com/v3/oauth/
Github users can create Personal Access Tokens at their application settings. You can use this token as an alternative to username/password in basic http authentication to call the API or to access private repositories on the github website.
Simply use a client that supports basic http authentication. Set the username equal to the token, and the password equal to x-oauth-basic. For example with curl:
curl -u <token>:x-oauth-basic https://api.github.com/user
See also https://developer.github.com/v3/auth/.
Send A POST request to /authorizations
With headers
Content-Type: application/json
Accept: application/json
Authorization: Basic base64encode(<username>:<password>)
But remember to take Two factor Authentication in mind
https://developer.github.com/v3/auth/#working-with-two-factor-authentication
Here You will receive a token which can be used for further request
Follow this guide at help.github.com. It describes how to find your api-token (it's under "Account Settings" > "Account Admin") and configuring git so it uses the token.
Here is the code to use GitHub Basic Authentication in JavaScript
let username = "*******";
let password = "******";
let auth = "Basic " + new Buffer(username + ":" + password).toString("base64");
var options = {
host: 'api.github.com',
path: '/search/repositories?q=google%20maps%20api',
method: 'GET',
headers: {
'user-agent': 'node.js',
"Authorization": auth
}
};
var request = https.request(options, function (res) {
}));