I'm building a FastAPI application with OAuth2 and JWT authentication. I've got two endpoints that create the JWT token. The first is hidden from the OpenAPI page but is used by the page Authorize button. The second does the same functionality but is available to the users as an API endpoint.
If the user uses the page Authorize button and successfully gets authenticated, the rest of the API endpoints on the OpenAPI page become accessible.
If the user uses the API get_token endpoint only, they get a valid JWT token, which can be used with the protected API's, but the OpenAPI page isn't authenticated.
How can I use the token returned by the public get_token API endpoint to authenticate the OpenAPI page as if the user went through OpenAPI provided Authorize functionality?
When using the Authorize button, the Authorization header with the token in it is automatically sent in every subsequent request you make to the FastAPI backend, and hence, the user gets authenticated.
Using your get_token endpoint, users will obtain the token as a response, and have to manually place it in the headers for every request they make. As described in this answer, as Authorization is a reserved header in Swagger UI/OpenAPI specification, you either have to define a Header parameter in your endpoints with a different name, e.g., token (where users will place the token value), or use the Authorize button, which will automatically add it for every request to any endpoint of your server.
Another option would be to create an httponly cookie (using the Set-Cookie header) with the token inside once the user calls the get_token endpoint, and return the cookie with the Response object, as described here and here. The browser will store the cookie sent by the server and will send it back with every request made to the server inside a Cookie HTTP header (read more about cookies here). Inside the endpoint, you can then retrieve the token using the Request object directly, for example, request.cookies.get('token'), or by defining a cookie parameter for it.
Related
I've got a tiny function that just looks to get a response from my DRF API Endpoint.
My DRF settings look like this:
"DEFAULT_AUTHENTICATION_CLASSES": [
# Enabling this it will require Django Session (Including CSRF)
"rest_framework.authentication.SessionAuthentication"
],
"DEFAULT_PERMISSION_CLASSES": [
# Globally only allow IsAuthenticated users access to API Endpoints
"rest_framework.permissions.IsAuthenticated"
],
I'm using this to try and hit the endpoint:
def get_car_details(car_id):
headers = {"X-Requested-With": "XMLHttpRequest"}
api_app = "http://localhost:8000/"
api_model = "cars/"
response = requests.get(api_app + api_model + str(car_id), headers=headers)
json_response = response.json()
return json_response
I keep getting 'detail': 'Authentication credentials were not provided'
Do I need to generate a CSRF token and include it in a GET request? The only time this gets hit is when a user goes to a view that requires they are logged in. Is there a way to pass that logged-in user to the endpoint??
When you make your request from the get_car_details function you need to be sure that the request is authenticated. This does not look like a CSRF issue.
When using session based authentication a session cookie is passed back after logging in. So before you call get_car_details you would need to first make a request to login, keep that session, and use that session when calling the API.
Requests has a session class requests.Session() that you can use for this purpose. Details here: https://docs.python-requests.org/en/latest/user/advanced/
Many people find token based authentication easier partly a session cookie does not need to be maintained.
Please help. I am trying to search for a specific user in Foursquare but for some reason I got Missing credentials error 401.
user_id = '484542633' # user ID with most agree counts and complete profile
url = 'https://api.foursquare.com/v2/users/{}?client_id={}&client_secret={}&v={}'.format(user_id, CLIENT_ID, CLIENT_SECRET, VERSION) # define URL
# send GET request
results = requests.get(url).json()
user_data = results['response']['user']
# display features associated with user
user_data.keys()
As documentation states, this endpoint is meant to be accessed on behalf of the user:
This endpoint requires user authentication.
User calls require a valid OAuth access token in the query string of each request instead of the Client ID and Secret (&oauth_token=XXXX).
For more information about this authentication method and how to obtain an access token, see the Authentication docs.
This means v2/users can only be accessed by your app, after a user (which can be you, using your own Foursquare account) goes through the OAuth login flow and grants necessary permissions. OAuth doesn't mean your app "logs in" as the user, rather that the user has given you permission to do something on their behalf.
To learn more about OAuth you can watch this talk: https://www.youtube.com/watch?v=996OiexHze0
To read more about Foursquare's API visit their documentation site: https://developer.foursquare.com/docs/api/
I'm looking to propagate a JWT token between my services running in docker using the library flask-jwt-extended and I have an idea of how I would do this using something similar to this:
request.post(url, json={"access_token": access_token, "refresh_token": refresh_token)
But in my experience I need to return a response to do this.
I already have the frontend creating tokens and protecting my routes. I just want to use that token to do the same for the backend.
I want to be able to login from my frontend application and when I login that propagates the token throughout the other services. How do I approach this?
I will send the post request to a function that will look something similar to this:
#app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == "POST":
resp = jsonify({'login': True})
set_access_cookies(resp, request.json["access_token"])
set_refresh_cookies(resp, request.json["refresh_token"])
return resp, 200
Do I need to return that response?
Token sharing should be accomplished via signature trust. Make sure that your other services "know" the public key of the trusted signer.
Here's the basics:
Frontend requests token from backend via authorization api
Backend validates credentials, issues token using 'RSXXX' algorithm, eg. 'RS512'
Frontend passes token to all calls to any of your backend services.
When backend receives a token it verifies signature and "source" using the public key identity of the token before applying token payload to the requested operation.
All backend services and the frontend should have a configuration element which defines one or more trusted public keys used for token signing.
This article has some helpful information on using a public/private key pair with pyjwt:
https://blog.miguelgrinberg.com/post/json-web-tokens-with-public-key-signatures
I was able to get the callback with the redirect_uri and auth code and I was able to authorize the user and redirect him but I am not getting the account_linking in the request object after successful login ie.., I want to check whether the user is logged in or not for every message he sends.
The account linking feature does not support this type of token validation. You would need to send a request to your auth server to check if the person is still logged in.
I'm trying to make a login with Facebook.
What I want is to create and endpoint and use it as I use the "standard" email login endpoint, since I need a big separation between the backend and the frontend.
I think it should be easy to do it, but I don't know how to do it.
I read this and when I use the Url in the browser, it works properly and I get the token in the response Url. But, it happens always on the frontend side.
I tried many tutorials this one is an example, and it works, but I'm the backend, I'm not allowed to have something like that, as the frontend is written in Django too.
So, I don't know how should be the workflow when you're just the Backend, I don't know what the Frontend developers wait from me because the authentication happens actually on the frontend side.
And I'm a little bit lost.
Maybe someone had the same problem as Backend and could help me, at least tell me, how the workflow backend - frontend should be.
Facebook JavaScript/Android/iOs SDKs lets the client to authenticate the users. Once the user is authenticated with facebook, your clients can send the accessToken through a HTTP POST over https.
This is what I have done in a similar situation,
At backend,
Create API endpoint to authenticate user by validating their accessToken,
POST /auth/
Use this endpoint to verify the accessToken sent by the client. The token should be validated calling Facebook services with your app secret. Once done validating, return a response as a JSON detailing the status of the authentication and user identification details if successful.
on the request,
body should contain accessToken as a key/or a header
Content-Type header should be application/json
any additional expected headers must be validated
on the request try to include
status of the operation
user identification detail if operation is success
a JWT or some sorta token to identify the user which users can include in Authorization header, so that you can validate the request just buy validating the token against User. Set an expiry as the accessToken if JWT is expired, refresh accessToken at client side and validate again.
At Frontend.
Let the client do the following to authenticate themselves.
send accessToken to /auth as a POST request.
if authentication status is success, let them store the JWT in locally and use it on the upcoming requests.
at backend on upcoming calls,
if token is expired or tampered, redirect client to authenticate with Facebook again.
on logging out of user, delete the token from client.
So for the frontend developers,
Document your API properly and share it with them