Flask AppBuilder: accept JWT bearer token for service account - flask

I am working with Superset, although this applies to Flask AppBuilder (FAB) in general.
I can configure a Flask / FAB app to use OAuth2 or OIDC via flask-oidc or fab-oidc package.
For end users this works fine, following this example
I would also like a service account to call backend APIs with a JWT Bearer token from the same identity provider, obtained through client credentials flow.
It looks like Flask AppBuilder can look for a JWT in the request via flask-jwt-extended, but has no knowledge of the identity provider configuration used for end-user browser-based authentication.
What's a good way to get the OAuth2 identity configuration applied to bearer tokens as well as end users?
It feels like this should be possible somehow via the custom SecurityManager but I'm not sure what the right extension point is.
It's like, somehow, I want the FAB #protect annotation to work with the flask-oidc #oidc.accept_token annotation, but not sure how to connect the two.

Related

Access Django Rest API using Azure access token and SimpleJWT access token

Need just hint, tried all possible ways.
Any approach is highly appreciated.
Problem statement: access jwt authenticated django rest api using azure ad access token in postman and local app. django app is hosted on azure app service.
Challenge: pass two token with different header values in authorisation header such that azure token is also reader with django jwt token.
A. All possible authorisation in postman.
B. Different authorization keys and header values in django jwt settings
I've deployed my django application on azure app service.
I'm using JWT authentication for all rest API's.
I've an azure directory and service principal linked to azure web app.
In postman,
I can get access token from azure active directory(using clientID, Secret, resource, etc.) and use the same token to call django rest api.
I can easily access unauthenticated API just by using azure access taken in authorization bearer header.
For JWT authenticated API, I'm not able to use them (crud operation) as none of my approach is working.
Azure access token header value : Bearer
Django JWT token header value: Bearer, Token, JWT.
---- EDIT ----
Django application will server as a backend to client applications. Thus client application have to generate azure token and provide while calling django app API. But django application API's are also authenticted with JWTAuthentication, thus 2 tokens have to provided.
Problem
Both Tokens have to be provided in 'Authorisation' key to use with HTTP_AUTHORISATION.
INFORMATION
JWT packages: simplt_jwt
simplt_jwt,django version: latest
client: react-js webapp, swift ios mobile app
resources: azure app service, azure active directory with service plan
django website is used as a backend for webapp and mobile app.
To elaborate, some images are added:
Need to use this architecture (api endpoint with jwt authentication):
Call an API with JWT authentication header value in (Bearer, Token, JWT), and have to provide Azure access token withheader value as (Bearer).
Both Tokens have to be provided in authorisation header.
[api endpoint with jwt authentication][1]
[1]: https://i.stack.imgur.com/y0Uvf.png
Called an API(wihout django JWT authentication) using only azure access token and was able to get response.
Correct me if I'm using some wrong approach.
Add another custom backend and verify your Azure token by its public key:
https://docs.djangoproject.com/en/4.1/topics/auth/customizing/
And add it next to your SimpleJWT auth backend.
In your settings.py file:
REST_FRAMEWORK = {
...
'DEFAULT_AUTHENTICATION_CLASSES': (
...
'rest_framework_simplejwt.authentication.JWTAuthentication',
# add your azure backend here
'your_app.auth_azure_backend.AzureAuthentication',
)
...
}
from django.contrib.auth.backends import BaseBackend
class AzureAuthentication(BaseBackend):
def authenticate(self, request, token=None):
azure_token = request.headers['AzureToken'] # you can use custom headers or just use `Authentication` with Bearer token. Django will go through every backend to verify it.
decoded = jwt.decode(azure_token, public_key, algorithms=["RS256"])
# return user instance based on decoded data from Azure
If you can decode without error that means your token is generated by Azure AD.
You can follow this question to get your public key https://learn.microsoft.com/en-us/answers/questions/793793/azure-ad-validate-access-token
So I found a solution, if wrong please provide feedback.
I have create an authentication class inheriting JWTAuthentication class. And reading custom headers in request.headers. this way I can provide multiple tokens in a request.
Actually, My application is hosted on azure app service. So have to authenticate send also application have some inbuilt authentication to manage user access, thus need token for the same.

django_auth_adfs: get JWT token for the client on successful authentication

I have a Django application that doesn't have MVC pages and most of the data is served/posted via restful API powered by django-rest-framework. My userbase is in Azure single tenant AD, so I am trying to get the SSO going for them.
I am using django_auth_adfs to authenticate users against the Azure AD. Most of the stuff seems to work and the module takes care of the redirects and establishing the Django sessions for the client. Specifying the right permission_classes for the API ViewSets will make sure only authenticated users can access it it works fine via browser with proper django session cookie.
What I can't figure out is how to get the JWT token that I can give the UI client so that it could interact with the django-rest-framework API by supplying the JWT bearer and not relying on the session.
The documentation is not very specific on these details (besides the password grant that isn't quite relevant for my scenario).

How OAuth authorization works via API

It is clear how to get a token from Google(or any other OAuth provider). But I do not understand where shoud I do it - server part or client part.
For example: I have a backend on Flask with unified API for Android, iOS and web(js/react) apps.
Where do I need to get a token? On the client (Android for example) part and send it to server or in my Flask app after request from client? Where should I get data from provider? How at all works interaction between client and server while using OAuth?
Would be pleased for some explanations or links on some guides
Your UIs will manage redirecting the user to authenticate - after which the UI is given an access token to call the API with.
The OAuth provider is the entry point for authentication and issues an access token afterwards.
The API uses the access token to identify the user and authorize access to resources.
A good way to understand OAuth is the HTTP messages - my blog post highlights these, and they are largely the same for SPAs and mobile.
There are also some code samples on my blog which you can run, in case useful.

Web API authentication using OAuth 2.0 token and Azure Active Directory (Without Authentication Server)

Is there a way to authenticate the Microsoft or google OAuth token in active directory without using an authentication server?
Here is the scenario:
A client app gets an Microsoft access_token from some external service.
Client app will make a call to some secured web API and pass that access_token along with the request header
If the access_token passed by client is valid then API will provide response to the client.
Is there a way to validate that access_token on API side?
My normal understanding about OAuth 2.0 is there needs to be an authentication server to which both the client and API would talk to as shown in the figure below:
But if the token is provided by some external service, Can we use it to validate our web API. Are there any ways to implement such authentication?
You can learn more about AAD Signing Keys and handling Key Rollover using this page: Signing key rollover in Azure Active Directory
Validation of the token, once you have the signing key, can be done using existing libraries like OWIN. You can also try following instructions like this (although it seems the document isn't 100% complete yet): Manually validating a JWT access token in a web API
This library is also available, but I think OWIN is supposed to have replaced it in general.
Also check out this blog post, which has a pretty great deep dive into token validation.

Generate an OAuth2 token in a view

Let's say I have an AngularJS application that consumes the REST API of a Django application.
The Django application has got a built-in OAuth2 provider that can be called to retrieve an access token and use the protected endpoints of the API. This provider is using django-oauth-toolkit.
Let's assume there is a registered client with "password" grant type, so that the end users only need to provide their credentials in the front-end in order to get an access token from the back-end.
At some point we want to add some support for social networks login and we decide to use python-social-auth (PSA) to that end. Here is the workflow I want to achieve:
The user logs in on Facebook from the front-end (via the Facebook SDK) and we get an access token back from the OAuth2 provider of Facebook.
We send the Facebook token to an endpoint of our REST API. This endpoint uses the Facebook token and django-social-auth to authenticate the user in our Django application (basically matching a Facebook account to a standard account within the app).
If the authentication succeeds, the API endpoint requests an access token from the OAuth2 provider for this newly authenticated user.
The Django access token is sent back to the front-end and can be used to access the REST API in exactly the same way that a regular user (i.e. logged in with his credentials) would do.
Now my problem is: how do I achieve step 3? I first thought I would register a separate OAuth2 client with Client Credentials Grant but then the generated token is not user-specific so it does not make sense. Another option is to use the TokenAuthentication from DRF but that would add too much complexity to my project. I already have an OAuth server and I don't want to set up a second token provider to circumvent my problem, unless this is the only solution.
I think my understanding of PSA and django-oauth-toolkit is not deep enough to find the best way of reaching my goal, but there must be a way. Help!
I managed to get something working using urllib2. I can't speak towards whether or not this is good practice, but I can successfully generate an OAuth2 token within a view.
Normally when I'd generate an access token with cURL, it'd look like this:
curl -X POST -d "grant_type=password&username=<user_name>&password=<password>" -u"<client_id>:<client_secret>" http://localhost:8000/o/token/
So we're tasked with making urllib2 accomplish this. After playing around for some bit, it is fairly straightforward.
import urllib, urlib2, base64, json
# Housekeeping
token_url = 'http://localhost:8000/auth/token/'
data = urllib.urlencode({'grant_type':'password', 'username':<username>, 'password':<password>})
authentication = base64.b64encode('%s:%s' % (<client_id>, <client_secret>))
# Down to Business
request = urllib2.Request(token_url, data)
request.add_header("Authorization", "Basic %s" % authentication)
access_credentials = urllib2.urlopen(request)
json_credentials = json.load(access_credentials)
I reiterate, I do not know if this is in bad practice and I have not looked into whether or not this causes any issues with Django. AFAIK this will do this trick (as it did for me).