Django doesn't validate or see the JWT token from Azure - python

I used azure-ad-verify-token 0.2.1 on Django-rest backend to validate a jwt token from Microsoft Azure, where the user is authenticated on the frontend with React.
According to the documentation, this library should do everything on its own.
from azure_ad_verify_token import verify_jwt
azure_ad_app_id = 'my app id'
azure_ad_issuer = 'https://exampletenant.b2clogin.com/0867afa-24e7-40e9-9d27-74bb598zzzzc/v2.0/'
azure_ad_jwks_uri = 'https://exampletenant.b2clogin.com/exampletenant.onmicrosoft.com/B2C_1_app_sign_in/discovery/v2.0/keys'
payload = verify_jwt(
token='<AZURE_JWT_TO_VERIFY_HERE>',
valid_audiences=[azure_ad_app_id],
issuer=azure_ad_issuer,
jwks_uri=azure_ad_jwks_uri,
verify=True,
)
print(payload)
I don't understand the line token='<AZURE_JWT_TO_VERIFY_HERE>', how can I put the token there?
Authorization from Azure on React is successful, and I get a access jwt-token that I can extract:
token = request.headers['Authorization']
But I need to validate it and somehow insert it into a string token='<AZURE_JWT_TO_VERIFY_HERE>', but it doesn't recognize the request here.
How can I put a token= from the header?
And in general, is this the right way? Or am I missing something? Any help and hints would be very helpful and would be greatly appreciated. Or advise another library for token validation in Python.

azure-ad-verify-token This is used to verify the tokens received from azure ad.
You have to get auth tokens from azure using MSAL python library and the azure-ad-verify-token will then verify the token.
To retrieve the tokens, you will need MSAL python library, and it
will also take clientid and tenentd as arguments.
test_app=PublicClientApplication(client_id=client_id,authority="https://login.microsoftonline.com/"+tenant_id)
test_tokens=test_app.acquire_token_interactive(scopes=scopes)
Now you can take the token you just received and use it in theazure-ad-verify-token.
token=test_tokens['access_token']
Reference:
MSAL Python
Authenticate Python apps by using the Azure SDK for Python

Related

Firebase admin SDK Python - cannot verify custom tokens

I'm trying to play with the firebase admin sdk for python for making custom tokens and verify those while testing my app. Problem is that while I try to verify the token I always get such an error:
ValueError: Firebase ID token has incorrect "aud" (audience) claim. Expected "my_project_id" but got "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit". Make sure the ID token comes from the same Firebase project as the service account used to authenticate this SDK. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.
I followed the guide to create the app and making the tokens:
import firebase_admin
from firebase_admin import auth, credentials
cred = credentials.Certificate('/path/to/file.json')
app = firebase_admin.initialize(cred)
custom_token = auth.create_custom_token('some-uid', app=app)
auth.verify_id_token(custom_token, app=app)
and here I get the error. It seems that _TokenGenarator is initialised with the defaults that are coming back from the error. I thought when passing the app it should automatically change those but it's not happening. Am I missing something?
verify_id_token() only accepts ID tokens. Custom tokens do not fall into that category. See this test case. Raising a ValueError is the expected behavior in this case.
ID tokens can be obtained from a client SDK. You can exchange a custom token for an ID token by calling one of the provided signInWithCustomToken() methods.

Verify Firebase idToken via Python

I'm using Firebase for the first time and am unable to verify that a user is authenticated from the Firebase idToken.
I've attempted to use Google App Engine's example in flask: https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/appengine/standard/firebase/firenotes.
I've also tried using python libraries mentioned by Firebase here: https://jwt.io/
Any help would be greatly appreciated.
Simply to identify a user you have to send the token that generates javascript as a header in the request to the server
Authorization:key=eyJhbGc .... ZgeFONFh7HgQ
id_token = request.headers['Authorization'].split('=').pop()
Once you have that token with the library google.oauth2.id_token will ask for the UID of that generated token
claims = google.oauth2.id_token.verify_firebase_token(id_token, HTTP_REQUEST)
If not claims:
         Return 'Unauthorized', 401
UID = claims['sub']
Already with that UID is like your PK in any DB that you use

Getting user info with Cloud Endpoints (using other API Endpoints)

I'm trying to setup endpoints api (with google app engine, python), but I'm having some trouble getting user profile info. API is working, I can create entities through API Explorer on my localhost.
My goal is to allow user to register for my app by providing just an email, and authorizing the app to get the reset of the info from their profile. I have this endpoints method:
#User.method(http_method="POST",
auth_level=endpoints.AUTH_LEVEL.REQUIRED,
allowed_client_ids=[
endpoints.API_EXPLORER_CLIENT_ID
],
scopes=[
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/plus.me',
],
user_required=True,
request_fields=('email',),
response_fields=('id',),
name="register",
path="users")
def UserRegister(self, instance):
logging.info(os.getenv( 'HTTP_AUTHORIZATION' ))
# 'Beared __TOKEN__'
logging.info(endpoints.users_id_token._get_token(None))
# '__TOKEN__'
instance.put()
return instance
This works fine, I receive authorization token and user is created in datastore, but I can't figure out how to get the profile info. If I enter the token in OAuth2 API (through API Explorer):
POST https://www.googleapis.com/oauth2/v2/tokeninfo?access_token=__TOKEN__
I get token info with some data I need { "user_id": "__ID__", "verified_email": true, ...}, and if I use user_id in +API:
GET https://www.googleapis.com/plus/v1/people/__ID__
I can get the rest of the data I need (name, image, etc).
What do I need to do to achieve this in my UserRegister() method? I'd prefer to return just entity ID and do the rest of registration asynchronously, but that's another issue, I'll figure it out (; Just need some guidance how to call other endpoints from my code...
EDIT:
I've managed to figure out how to call other APIs (code on Gist), now only have one issue with Plus API:
I did some queries and eventually got anonymous quota error. Then I added key parameter and set it to WEB_CLIENT_ID or SERVICE_ACCOUNT:
WEB_CLIENT_ID is OAuth2 Client ID (type: Web Application) from console.developers.google.com/apis/credentials,
SERVICE_ACCOUNT is default App Engine service account - MY_APP#appspot.gserviceaccount.com...
and now I'm getting following error:
HttpError: <HttpError 400 when requesting https://www.googleapis.com/plus/v1/people/__VALID_USER_ID__?key=__WEB_CLIENT_ID__or__SERVICE_ACCOUNT__&alt=json returned "Bad Request">
When I use +API explorer I get results as expected:
REQUEST:
https://www.googleapis.com/plus/v1/people/__VALID_USER_ID__?key={YOUR_API_KEY}
RESPONSE:
200 OK + json data for user...
Anyone knows why is this happening?
Why am I getting BadRequest response?
Problem with BadRequest was that I didn't send authorization token... I did try to send it as access_token, but seams like +api docs are outdated - it should be oauth_token. When I included this parameter issue was resolved:
build('plus', 'v1').people().get(userId=user_id, key=SERVICE_ACCOUNT, oauth_token=token).execute()
HINT: Use http://localhost:8001/_ah/api/discovery/v1/apis/, and discoveryRestUrl property it has to see real properties of your API - this is where I found the answer.
oauth_token can be obtained like this:
token = os.getenv('HTTP_AUTHORIZATION').split(" ")[1]
# or like in my question:
token = endpoints.users_id_token._get_token(None)
I'd suggest HTTP_AUTHORIZATION variable, because users_id_token docs state that it's a:
Utility library for reading user information from an id_token.
This is an experimental library that can temporarily be used to extract
a user from an id_token. The functionality provided by this library
will be provided elsewhere in the future.
How to call other API Endpoints?
This is also an answer to my first question:
from googleapiclient.discovery import build
service = build('plus', 'v1')
request = service.people().get(userId=user_id, key=SERVICE_ACCOUNT, oauth_token=token)
response = request.execute()
data = dict(self.response.POST)
Code that worked for me is here.
NOTE: WEB_CLIENT_ID obtained from https://console.developers.google.com/apis/credentials (OAuth2 Client ID of type Web Application) will NOT work in this case. I had to use SERVICE_ACCOUNT - I didn't try to generate one through console, default service account I got from App Engine worked fine.
...things are much clearer now that I got this working. Hope it will help someone else (;

Move Google EmailSettings API python code from OAuth1 to OAuth2 service account

To use the new Google Directory API we created an OAuth2 "service account" (see Using OAuth 2.0 for Server to Server Applications). This is basically a PKCS #12 file. All of our Directory API scripts work fine with this service account.
We also use the EmailSettings API (Developer's Guide Email Settings API) to manage some of our Google account settings. These scripts did not move to the new API format, so we continue to use the old OAuth1 authentication method. This has, until recently, worked fine. However, it appears that Google is no longer supporting OAuth1 authentication.
So, we need to move the EmailSettings scripts from OAuth1 to our OAuth2 service account. We are using the gdata Python libraries (GitHub google/gdata-python-client) to make calls to the EmailSettings API. This is how we currently authenticate to make EmailSettings API calls:
import gdata.apps.emailsettings.service
# self is an EmailSettingsService object (gdata.apps.emailsettings.service)
self.domain = "mydomain.com"
self.source = "my application name"
token = get OAuth1 token string from a file
self.SetOAuthInputParameters(
gdata.auth.OAuthSignatureMethod.HMAC_SHA1,
consumer_key = token.oauth_input_params._consumer.key,
consumer_secret = token.oauth_input_params._consumer.secret
)
token.oauth_input_params = self._oauth_input_params
self.SetOAuthToken(token)
Using these Python gdata libraries, how do I authenticate using our OAuth2 service account, i.e., the PKCS #12 file, to use the EmailSettings API?
There's another SO question which shows you how to do this but uses the slightly newer gdata.apps.emailsettings.client methods.
If you must stay with gdata.apps.emailsettings.service then you can "hack" OAuth 2.0 onto the object with something like:
Build your OAuth 2.0 credentials object as you are already doing for your Admin SDK Directory API calls.
Build your GData client object as you are already doing in lines 1-3 of your code.
Grab the access token from your credentials object and apply it as a header to your client object:
client.additional_headers = {
'Authorization': u'Bearer %s' % credentials.access_token}
If you get a 401 response (access token expired), repeat 1 and 3 to get and apply a new access token.

OAuth2 client that works on App Engine

Can anyone advice me on a good library or else how to go about having a Python appengine based application using OAuth to authenticate to another server?
I have an application on appengine that expects user input. I would like the user to be able to upload an image, which I would put in imgur.com and would be able to show to the user back on my page. To be able to do that, I need to be able to authenticate to api.imgur.com hence the question.
Have a look to python-oauth2 project.
A Client example:
import oauth2 as oauth
# Create your consumer with the proper key/secret.
consumer = oauth.Consumer(key="your-twitter-consumer-key",
secret="your-twitter-consumer-secret")
# Request token URL for Twitter.
request_token_url = "http://twitter.com/oauth/request_token"
# Create our client.
client = oauth.Client(consumer)
# The OAuth Client request works just like httplib2 for the most part.
resp, content = client.request(request_token_url, "GET")
print resp
print content
I believe the simplegeo oauth2 does not play well with GAE. Mike Knapp's library on GitHub is nice and simple, no install needed.
maybe you can use imgur-api, http://code.google.com/p/imgur-api/wiki/ImageUploading

Categories