tokusumi / fastapi-cloudauth Goto Github PK
View Code? Open in Web Editor NEWSimple integration between FastAPI and cloud authentication services (AWS Cognito, Auth0, Firebase Authentication).
License: MIT License
Simple integration between FastAPI and cloud authentication services (AWS Cognito, Auth0, Firebase Authentication).
License: MIT License
Awesome initiative, that's just what I've been looking for
It would be nice if you can provide support for the ORY stack as well (https://www.ory.sh/).
I will give a try on my projects!
Thanks a lot!
Does this package have Google login? Or who can tell me how to integrate google login
on pypi the fastapi requirement is listed as 'fastapi>=0.60.1,<0.61.0', so doesn't allow the latest version.
Any chance of getting that bumped up?
(Would do a pr but can't see in this repo where it's specified)
Hey,
I just can't get cognito to work with this library...
I am using the second example
def secure_access(current_user: AccessUser = Depends(auth.claim(AccessUser))):
# access token is valid and getting user info from access token
return f"Hello", {current_user.sub}
with the example
class AccessUser(BaseModel):
sub: str
But as soon as I add custom attributes that are set in my cognito pool, like "email" or "family_name", it throws the error
"Validation Error for Claims"
How can I add custom attributes to grab them like current_user.family_name ?
Hey guys so I wanted to request this feature that I think might be an interesting addition to the library that consists of adding on the Authorization documentation of each request under "HTTP Authorization Scheme" a new row called "Scopes Accepted/Required" where it would be a list of the scopes the backend requires for the request to be accepted.
If you guys could point me to where I could start exploring this feature I might be able to develop my self and contribute but right now Im not sure where does the library define documentation sections.
Thank you for your work on this library, it simplified the standard use case of authentication for my API by a lot.
However, the documentation on RBAC and verifying claims is currently rather minimal and I was not able to figure out how to implement it.
Specifically I do not understand the following line: Use as (auth is this instanse and app is fastapi.FastAPI instanse):
What exactly is auth an instance of for the Firebase case and how can I get it?
Once solved, I can create a PR with some additional explication to the readme for clarification.
I tried replicating the tests and they all pass in theory, but I noticed the permissions fail to set (403 response).
collecting ...
-------------------------------------------------------------------------------- live log collection --------------------------------------------------------------------------------
DEBUG urllib3.connectionpool:connectionpool.py:971 Starting new HTTPS connection (1): awsvideo.eu.auth0.com:443
DEBUG urllib3.connectionpool:connectionpool.py:452 https://awsvideo.eu.auth0.com:443 "POST /dbconnections/signup HTTP/1.1" 200 None
DEBUG urllib3.connectionpool:connectionpool.py:971 Starting new HTTPS connection (1): awsvideo.eu.auth0.com:443
DEBUG urllib3.connectionpool:connectionpool.py:452 https://awsvideo.eu.auth0.com:443 "POST /oauth/token HTTP/1.1" 200 None
DEBUG urllib3.connectionpool:connectionpool.py:971 Starting new HTTPS connection (1): awsvideo.eu.auth0.com:443
DEBUG urllib3.connectionpool:connectionpool.py:452 https://awsvideo.eu.auth0.com:443 "POST /oauth/token HTTP/1.1" 200 None
DEBUG urllib3.connectionpool:connectionpool.py:971 Starting new HTTPS connection (1): awsvideo.eu.auth0.com:443
DEBUG urllib3.connectionpool:connectionpool.py:452 https://awsvideo.eu.auth0.com:443 "POST /oauth/token HTTP/1.1" 200 None
DEBUG urllib3.connectionpool:connectionpool.py:971 Starting new HTTPS connection (1): awsvideo.eu.auth0.com:443
DEBUG urllib3.connectionpool:connectionpool.py:452 https://awsvideo.eu.auth0.com:443 "POST /api/v2/users/auth0%7C5fe724da128f9f00699d0c67/permissions HTTP/1.1" 403 None
DEBUG urllib3.connectionpool:connectionpool.py:971 Starting new HTTPS connection (1): awsvideo.eu.auth0.com:443
DEBUG urllib3.connectionpool:connectionpool.py:452 https://awsvideo.eu.auth0.com:443 "POST /oauth/token HTTP/1.1" 200 None
DEBUG urllib3.connectionpool:connectionpool.py:971 Starting new HTTPS connection (1): awsvideo.eu.auth0.com:443
DEBUG urllib3.connectionpool:connectionpool.py:452 https://awsvideo.eu.auth0.com:443 "POST /oauth/token HTTP/1.1" 200 None
DEBUG urllib3.connectionpool:connectionpool.py:971 Starting new HTTPS connection (1): awsvideo.eu.auth0.com:443
DEBUG urllib3.connectionpool:connectionpool.py:452 https://awsvideo.eu.auth0.com:443 "POST /oauth/token HTTP/1.1" 200 None
DEBUG urllib3.connectionpool:connectionpool.py:971 Starting new HTTPS connection (1): awsvideo.eu.auth0.com:443
DEBUG urllib3.connectionpool:connectionpool.py:452 https://awsvideo.eu.auth0.com:443 "GET /.well-known/jwks.json HTTP/1.1" 200 None
DEBUG urllib3.connectionpool:connectionpool.py:971 Starting new HTTPS connection (1): awsvideo.eu.auth0.com:443
DEBUG urllib3.connectionpool:connectionpool.py:452 https://awsvideo.eu.auth0.com:443 "GET /.well-known/jwks.json HTTP/1.1" 200 None
DEBUG urllib3.connectionpool:connectionpool.py:971 Starting new HTTPS connection (1): awsvideo.eu.auth0.com:443
DEBUG urllib3.connectionpool:connectionpool.py:452 https://awsvideo.eu.auth0.com:443 "GET /.well-known/jwks.json HTTP/1.1" 200 None
DEBUG urllib3.connectionpool:connectionpool.py:971 Starting new HTTPS connection (1): awsvideo.eu.auth0.com:443
DEBUG urllib3.connectionpool:connectionpool.py:452 https://awsvideo.eu.auth0.com:443 "GET /.well-known/jwks.json HTTP/1.1" 200 None
collected 14 items
tests/test_auth0.py::test_valid_token
----------------------------------------------------------------------------------- live log call -----------------------------------------------------------------------------------
DEBUG asyncio:selector_events.py:59 Using selector: KqueueSelector
PASSED [ 7%]
tests/test_auth0.py::test_no_token PASSED [ 14%]
tests/test_auth0.py::test_incompatible_kid_token PASSED [ 21%]
tests/test_auth0.py::test_no_kid_token PASSED [ 28%]
tests/test_auth0.py::test_not_verified_token PASSED [ 35%]
tests/test_auth0.py::test_valid_scope PASSED [ 42%]
tests/test_auth0.py::test_invalid_scope PASSED [ 50%]
tests/test_auth0.py::test_get_current_user PASSED [ 57%]
tests/test_auth0.py::test_not_verified_user_no_error PASSED [ 64%]
tests/test_auth0.py::test_insufficient_current_user_info PASSED [ 71%]
tests/test_auth0.py::test_insufficient_current_user_info_no_error PASSED [ 78%]
tests/test_base.py::test_raise_error_invalid_set_scope PASSED [ 85%]
tests/test_base.py::test_return_instance_with_scope PASSED [ 92%]
tests/test_base.py::test_forget_def_user_info PASSED [100%]
================================================================================ 14 passed in 4.44s =================================================================================
hi, is there any way to pull the cognito id from the payload when the access token is valid?
So I implemented my apis with Cognito and this library and everything works really well but I have a couple requests that I wanted to chose what data to return based on the scope of the user. For example if the user scope is admin return all entries but if not only return the entries for that user.
Is this possible with this library?
Hello! congrats for the library.
I can see that there is no exception handling for malformed tokens so currently in my application I'm receiving a JWTError
from the jose library in some cases which ends up in a 500 error.
I would expect to be handle at https://github.com/tokusumi/fastapi-cloudauth/blob/master/fastapi_cloudauth/base.py#L77
I cannot see an easy and clean way to solve it without overwrite half of the classes I am using. Am I missing something?
Thanks!
I am looking for a way to make use of this package for Websockets?
Is there an example available how to accomplish this?
When using CognitoCurrentUser(region=settings.aws_region, userPoolId=settings.aws_cognito_user_pool_id)
in my endpoint depencies, it consistently errors a 403: "Validation Error for Claims". Further investigation indicated this has to do with an issue mapping the Cognito reply to the CognitoClaims Pydantic model here:
fastapi-cloudauth/fastapi_cloudauth/base.py
Line 232 in a8db880
The ValidationError is:
ValidationError(model='CognitoClaims', errors=[{'loc': ('cognito:username',), 'msg': 'field required', 'type': 'value_error.missing'}])
and indeed, the 'cognito:username' field is not available in the claims:
{'sub': '5a8b7ac6-5cd3-4279-b89b-5f59ca6c4144', 'cognito:groups': ['Users'], 'iss': '[Redacted]', 'version': 2, 'client_id': '[Redacted]', 'event_id': 'b0fcb01a-971b-40fe-942c-550dbf0915d2', 'token_use': 'access', 'scope': 'openid email', 'auth_time': 1614092323, 'exp': 1614095923, 'iat': 1614092323, 'jti': '48884493-8fad-47e5-8d8b-a4f44aa41900', 'username': '5a8b7ac6-5cd3-4279-b89b-5f59ca6c4144'}
but 'username' is!
I wasn't able to find why Cognito returns the claims in this different way.
class CognitoClaims(BaseModel):
username: str = Field(alias="cognito:username")
email: str = Field(None, alias="email")
class Config:
allow_population_by_field_name = True
Adding the allow_population_by_field_name = True
in the CognitoClaims model config makes it compatible with this other Cognito output.
This took me a while to track down. I would sometimes get {"detail":"JWK public Attribute for authorization token not found"}
after 7 days of the fastapi instance being up. This hinted towards something expiring.
The firebase.JWKsVerifier
class sets self._jwks_to_key = jwks.keys
; where jwks
is a firebase.JWKS
instance. JWKS.firebase
is constructed like so:
@classmethod
def firebase(cls, url: str) -> "JWKS":
"""
get and parse json into jwks from endpoint for Firebase,
"""
certs = requests.get(url).json()
keys = {
kid: jwk.construct(publickey, algorithm="RS256")
for kid, publickey in certs.items()
}
return cls(keys=keys)
What this means is the keys are queried with certs = requests.get(url).json()
and stored for as long as the instance is up, but they are never refreshed.
@tokusumi I can raise a PR to fix this if you're too busy; but i'd like your take on how to proceed with it. I'm not sure where to even do the detection for expired keys.
First of all I have to admit that I don't fully grasp all the oauth2 and OIDC concepts, which is probably why I stumbled accross this project to begin with, not knowing how to implement all the details myself.
Anyway, I've been reading auth0 documentation and this source code and I see it's possible to retrieve user email using Auth0Claims
. But these claims are valid only if FastAPI gets an id_token as Bearer, which is recommended against in this article: https://auth0.com/blog/why-should-use-accesstokens-to-secure-an-api/ that mentions id_token
is only meant for the client (which I understand is the frontend, not FastAPI).
I would love to find a reason why the official recommendation is not valid in this project.
In my fastapi API I need to know the user email for every request authorization. That's because I support multi-tenancy, where each user has CRUD access only to their own resources. I think this should be a fairly common scenario.. so I'm puzzled why there wouldn't be a straightforward way to do it.
When injecting the FirebaseClaims
object, no exception is raised for an unauthenticated user. It looks like it should raise a 401 exception because auto_error
is set to True
.
Additionally, it is unclear how to test this via the Swagger UI. There does not appear to be any authentication UI, as there is with cogito.
Code:
async def get_current_user(settings: Settings = Depends(get_settings)):
return FirebaseCurrentUser(project_id=settings.firebase_project_id)
@app.get("/protected")
async def protected(current_user: FirebaseClaims = Depends(get_current_user)):
return f"Hello, {current_user.user_id}"
Here I have attached the Image, I have used a firebase example and just try to run on ubuntu 20. x LTS
But it take long time to run while using on local machine (windows) it quickly run with in no time. is there any reason or is there any config where I am making mistake .
same code run on local (windows machine ) fine but take long time on cloud which uses ubuntu
Hi, firstly, thanks for the great library!
I'm wondering if there's currently any way to allow for the required scopes that are defined in the route decorator to be populated into the OpenAPI documentation that gets generated?
I'm guessing since this library uses the HTTPBearer security scheme rather then OAuth2 that the answer is currently "no". If so, is this something you'd look to add in future? It seems like a pretty handy feature for the API documentation to detail what scopes are required to access certain endpoints.
Hi, I've setup my fastapi-cloudauth as the readme describes in Example (AWS Cognito)
,
but can't see anywhere to specify my cognito callback URL
and I'm getting a 401 error with:
{
"detail": "JWK public Attribute for authorization token not found"
}
i'm calling my server like:
curl --location 'http://127.0.0.1:5000/access' \
--header 'Authorization: Bearer XXX
and my code is basically the hello world example:
import uvicorn
from pydantic import BaseModel
from fastapi import FastAPI, Depends
from fastapi_cloudauth.cognito import Cognito, CognitoCurrentUser, CognitoClaims
app = FastAPI()
auth = Cognito(
region="eu-xxxx,
userPoolId="eu-north-xxxx",
client_id="xxxx"
)
@app.get("/", dependencies=[Depends(auth.scope(["read:users"]))])
def secure():
# access token is valid
return "Hello"
class AccessUser(BaseModel):
sub: str
@app.get("/access/")
def secure_access(current_user: AccessUser = Depends(auth.claim(AccessUser))):
# access token is valid and getting user info from access token
return f"Hello", {current_user.sub}
get_current_user = CognitoCurrentUser(
region="eu-xxxx,
userPoolId="eu-north-xxxx",
client_id="xxxx"
)
@app.get("/user/")
def secure_user(current_user: CognitoClaims = Depends(get_current_user)):
# ID token is valid and getting user info from ID token
return f"Hello, {current_user.username}"
`
When I use your Python package, things work really well, so many thanks for it. 😀
However, there is one thing, where I ask myself, whether I can do much better here. When I try to reach my doc page, it looks like this:
When I click on the locking the top right, it looks like this
And after I enter the right token_id
, I can work with the doc page as intended.
However, getting the token_id
is quite cumbersome, as it usually involves curl requests etc.
It would be much nicer, if I am automatically logged in from Auth0, if I authenticated somewhere else in my browser. If I did not authenticate somewhere, then this here pops up
and after authenticating, I can work as intended. Is that possible?
Hi, thank you for you great work.
I have a question/feature request.
Currently, there is no straightforward way to pass user_info
into a respective UserInfoAuth
derived class (eg. CognitoCurrentUser
) before the instantinaion and only inheritance will work. So it'll be great to have something like this:
current_user_auth = CognitoCurrentUser(
region=settings.aws_region,
userPoolId=settings.userpool_id,
client_id=settings.app_client_id,
user_info=settings.user_info_class <---- here
)
The current implementation of CognitoCurrentUser
doesn't allow to do this.
It will be nice to have something like this:
class CognitoCurrentUser(UserInfoAuth):
"""
Verify ID token and get user info of AWS Cognito
"""
user_info = CognitoClaims
def __init__(
self,
region: str,
userPoolId: str,
client_id: str,
*args: Any,
**kwargs: Any,
):
url = f"https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json"
jwks = JWKS(url=url)
user_info = kwargs.get("user_info") or self.user_info <----- new code
super().__init__(
jwks,
user_info=user_info, <---- changes
audience=client_id,
issuer=f"https://cognito-idp.{region}.amazonaws.com/{userPoolId}",
extra=CognitoExtraVerifier(
client_id=client_id,
issuer=f"https://cognito-idp.{region}.amazonaws.com/{userPoolId}",
token_use={"id"},
),
*args,
**kwargs,
)
or be more explicit and add user_info
as a paramter to CognitoCurrentUser
__init__
method
Because of code like jwks = JWKS.fromurl(url)
in the __init__()
, it is impossible to import modules without them trying to connect to AWS Cognito at import time. This can cause a variety of problems, e.g. - unable to run unit tests without an Internet connection.
Hi,
Is it possible to catch the "Scope not matched" and display a more accurate message to the user.
`app.include_router(
manager.router,
prefix="/manager",
dependencies=[Depends(auth.scope('cognitogroup1))],
)
...
@router.get("/units")
def list_units(
current_user: AccessUser = Depends(auth.scope(['cognitogroup1']))
):
ret = [];
try:
print(current_user)
except:
raise
return "OK"
`
Hello,
Is there a way to extract user_id
from current user (Auth0) Auth0CurrentUser()
? For example, if I use:
get_current_user = Auth0CurrentUser("dev-some-domain.eu.auth0.com")
@router.get("/")
async def get_current_user(current_user=Depends(get_current_user)):
return current_user
as a result, I get a JSON object containing only name
and email
. Example:
{
"name": "[email protected]",
"email": "[email protected]"
}
Hi there,
Thank you for creating this package, I've been looking around for something like this over the past few months.
I'm wondering if you are actively working on the firebase integration and if so what your timeline is like?
I want to allow users only to access some APIs, if the e-mail of the user is verified. So far I have come up with that code
import os
from pydantic import Field
from fastapi import FastAPI, Depends
from fastapi_cloudauth.auth0 import Auth0CurrentUser, Auth0Claims
app = FastAPI()
class CustomAuth0Claims(Auth0Claims):
user_id: str = Field(alias="sub")
nickname: str = Field(alias="nickname")
is_verified: bool = Field(alias="email_verified")
get_current_user = Auth0CurrentUser(
domain=os.environ["AUTH0_DOMAIN"],
client_id=os.environ["AUTH0_CLIENTID"]
)
get_current_user.user_info = CustomAuth0Claims
@app.get("/user/")
def secure_user(current_user: Auth0Claims = Depends(get_current_user)):
# ID token is valid and getting user info from ID token
return f"Hello, {current_user}"
My question is now, how can I create something like get_current_user
, say get_current_verified_user
, which I can use for an API to enforce that only e-mail verified users are allowed to use it.
Hi there,
This is almost certainly user error & not a bug, as I'm new to Auth0.
In Auth0, I have configured an application (which is a VueJS client) set up as well as an API (my FastAPI back-end).
I've managed to get authentication working using the example def main_endpoint_test(current_user: AccessUser = Depends(auth.claim(AccessUser)))
- when I do this, I can get the user_id/sub, but I don't get the user email.
I tried using the other approach shown in the example: def secure_user(current_user: Auth0Claims = Depends(get_current_user)):
. When I use this, I always get a 401 response. I have initialised the get_current_user
passing in the domain
and client_id
as shown in the example - because the domain is working fine in the simpler auth method, maybe my mistake is entering the wrong value for the client_id
?
What is the client ID value should I be setting here, is it my Auth0 Application's client ID (i.e. the one for the VueJS client)? Is it the custom API's ID (as far as I can tell, there is no field explicitly labelled "client ID" in auth0's APIs)?
i have this code
async def init_auth(app: FastAPI) -> None:
logger.info("Auth: Configuring connection to {0}", repr(AUTH0_DOMAIN))
app.state.auth0_client = Auth0(domain=AUTH0_DOMAIN)
logger.info("Auth: Connection configured")
def _get_client(request: Request) -> Auth0:
return request.app.state.auth0_client
def get_auth() -> Callable:
return _get_client
init_auth
is triggered on app.add_event_handler("startup", init_auth(application))
then this code does work
@router.get("/something",
response_model=Any,
dependencies=[
Depends(get_auth)
]
)
async def get_something(
request: Request
):
return []
i would like to use auth.scope("read:something")
with Depends
but i can't seem to make it work
def get_auth_scoped(
*,
scope_name: str,
client: Auth0 = Depends(get_auth)
) -> Callable:
return client.scope(scope_name=scope_name)
and
@router.get("/something",
response_model=Any,
dependencies=[
Depends(get_auth_scoped(scope_name="read:something"))
]
)
async def get_something(
request: Request
):
return []
it results in a AttributeError: 'Depends' object has no attribute 'scope'
what am i missing here? please help?
Currently, it is only possible to define one scope to be checked.
@app.get("/access/")
def secure_access(scope=Depends(auth.scope("role_admin"))):
return f"Hello {scope}"
What i need is some way combine (and / or) multiple scopes.
cond = {"combinator": "or", "scopes": ["role_admin", "super_admin"]}
@app.get("/access/")
def secure_access(scope=Depends(auth.scope(cond))):
return f"Hello {scope}"
What do you think?
Hi,
I am trying to use the cognito plugin on robots in a place where internet connection is not stable.
In this case, the whole api won't load because auth is not loading properly. Click to expand the error.
I am confused on how I can handle it. You can reproduce it locally by cutting of the internet and trying to reload.
Having a try/except in the plugin, handle the timeout and return an error would be the solution. I'm trying to do it myself but doesn't seem so straightforward to me. Any idea how to proceed?
Thanks!
Process SpawnProcess-9:
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/urllib3/connection.py", line 169, in _new_conn
conn = connection.create_connection(
File "/usr/local/lib/python3.8/site-packages/urllib3/util/connection.py", line 73, in create_connection
for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM):
File "/usr/local/lib/python3.8/socket.py", line 918, in getaddrinfo
for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno -3] Temporary failure in name resolution
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 699, in urlopen
httplib_response = self._make_request(
File "/usr/local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 382, in _make_request
self._validate_conn(conn)
File "/usr/local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 1010, in _validate_conn
conn.connect()
File "/usr/local/lib/python3.8/site-packages/urllib3/connection.py", line 353, in connect
conn = self._new_conn()
File "/usr/local/lib/python3.8/site-packages/urllib3/connection.py", line 181, in _new_conn
raise NewConnectionError(
urllib3.exceptions.NewConnectionError: <urllib3.connection.HTTPSConnection object at 0x7fbb0d021d60>: Failed to establish a new connection: [Errno -3] Temporary failure in name resolution
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/requests/adapters.py", line 439, in send
resp = conn.urlopen(
File "/usr/local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 755, in urlopen
retries = retries.increment(
File "/usr/local/lib/python3.8/site-packages/urllib3/util/retry.py", line 574, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='cognito-idp.us-east-1.amazonaws.com', port=443): Max retries exceeded with url: /us-east-1_9n1ncAENJ/.well-known/jwks.json (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7fbb0d021d60>: Failed to establish a new connection: [Errno -3] Temporary failure in name resolution'))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
self.run()
File "/usr/local/lib/python3.8/multiprocessing/process.py", line 108, in run
self._target(*self._args, **self._kwargs)
File "/usr/local/lib/python3.8/site-packages/uvicorn/subprocess.py", line 61, in subprocess_started
target(sockets=sockets)
File "/usr/local/lib/python3.8/site-packages/uvicorn/main.py", line 407, in run
loop.run_until_complete(self.serve(sockets=sockets))
File "/usr/local/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
return future.result()
File "/usr/local/lib/python3.8/site-packages/uvicorn/main.py", line 414, in serve
config.load()
File "/usr/local/lib/python3.8/site-packages/uvicorn/config.py", line 300, in load
self.loaded_app = import_from_string(self.app)
File "/usr/local/lib/python3.8/site-packages/uvicorn/importer.py", line 20, in import_from_string
module = importlib.import_module(module_str)
File "/usr/local/lib/python3.8/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
File "<frozen importlib._bootstrap>", line 991, in _find_and_load
File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 783, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "./main.py", line 15, in <module>
from routers import (
File "./routers/account.py", line 4, in <module>
from core.cognito import auth
File "./core/cognito.py", line 46, in <module>
auth = Cognito(
File "/usr/local/lib/python3.8/site-packages/fastapi_cloudauth/cognito.py", line 24, in __init__
jwks = JWKS.fromurl(url)
File "/usr/local/lib/python3.8/site-packages/fastapi_cloudauth/verification.py", line 50, in fromurl
jwks = requests.get(url).json()
File "/usr/local/lib/python3.8/site-packages/requests/api.py", line 76, in get
return request('get', url, params=params, **kwargs)
File "/usr/local/lib/python3.8/site-packages/requests/api.py", line 61, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/local/lib/python3.8/site-packages/requests/sessions.py", line 542, in request
resp = self.send(prep, **send_kwargs)
File "/usr/local/lib/python3.8/site-packages/requests/sessions.py", line 655, in send
r = adapter.send(request, **kwargs)
File "/usr/local/lib/python3.8/site-packages/requests/adapters.py", line 516, in send
raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='cognito-idp.us-east-1.amazonaws.com', port=443): Max retries exceeded with url: /us-east-1_9n1ncAENJ/.well-known/jwks.json (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7fbb0d021d60>: Failed to establish a new connection: [Errno -3] Temporary failure in name resolution'))
I'm a "noob" where Cognito is concerned and could be missing something about accessing the example API's. I've got an AWS User Pool defined with a user created. How do I log that user in, or get a JWT Token to use to authorize the example API to access the endpoints?
Thanks for your help.
Hi, I am trying to make it work with Firebase.
I am using exaclty the same code you have in the examples
import os
from fastapi import FastAPI, Depends
from fastapi_cloudauth.firebase import FirebaseCurrentUser, FirebaseClaims
app = FastAPI()
get_current_user = FirebaseCurrentUser(
project_id="my-project-id"
)
@app.get("/user/")
def secure_user(current_user: FirebaseClaims = Depends(get_current_user)):
# ID token is valid and getting user info from ID token
return f"Hello, {current_user.user_id}"
but I have the following error:
File "./src/main.py", line 7, in <module>
get_current_user = FirebaseCurrentUser(
File "/home/elvis/Documents/dev-tools/API/env/lib/python3.9/site-packages/fastapi_cloudauth/firebase.py", line 28, in __init__
jwks = JWKS.firebase(url)
File "/home/elvis/Documents/dev-tools/API/env/lib/python3.9/site-packages/fastapi_cloudauth/verification.py", line 70, in firebase
keys = {
File "/home/elvis/Documents/dev-tools/API/env/lib/python3.9/site-packages/fastapi_cloudauth/verification.py", line 71, in <dictcomp>
kid: jwk.construct(publickey, algorithm="RS256")
File "/home/elvis/Documents/dev-tools/API/env/lib/python3.9/site-packages/jose/jwk.py", line 79, in construct
return key_class(key_data, algorithm)
File "/home/elvis/Documents/dev-tools/API/env/lib/python3.9/site-packages/jose/backends/rsa_backend.py", line 171, in __init__
raise JWKError(e)
jose.exceptions.JWKError: No PEM start marker "b'-----BEGIN PRIVATE KEY-----'" found
Any idea?
Thank you
Hi, maybe I am missing something obvious, but when authenticating using an auth token from cognito, the fastapi-cloudauth responds with 401 {"detail": "Not verified"}
This does not refer to the user I guess, as the user is email & phone verified, but does it refer to the domain (localhost, local dev)?
How would I test my app locally then?
I hope you can point me in the right direction, as this package would be awesome to use!
One of my endpoints for API receives cognito token as HTTP parameter instead of authentication header (Some issues sending authentication header on frontend). Other endpoints have been implemented just as described in Readme.
Is there any way to verify that token received as a string parameter using fastapi-cloudauth ?
Not so much an issue as a question, i wanted to work with a local cognito provider while running my service locally before connecting to cognito in production. I noticed I wasn't able to specify a local host url, looking closer into the code looks like its all hardcoded in the Cognito object. Is there anyway for me to specify the url or would i have to create a PR?
class Cognito(ScopedAuth):
"""
Verify access token of AWS Cognito
"""
user_info = None
def __init__(
self,
region: str,
userPoolId: str,
client_id: str,
scope_key: Optional[str] = "cognito:groups",
auto_error: bool = True,
):
url = f"https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json"
jwks = JWKS(url=url)
super().__init__(
jwks,
audience=client_id,
issuer=f"https://cognito-idp.{region}.amazonaws.com/{userPoolId}",
scope_key=scope_key,
auto_error=auto_error,
extra=CognitoExtraVerifier(
client_id=client_id,
issuer=f"https://cognito-idp.{region}.amazonaws.com/{userPoolId}",
token_use={"access"},
),
)
I faced with an issue when using congito auth, app client_id
is not validating during token verification. So you can path any ID and it will work.
# pass some fake client_id
auth = Cognito(region=aws_region, userPoolId=aws_cognito_userpool_id, client_id='foo-bar')
# access_token - obtained from Cognito
http_auth = HTTPAuthorizationCredentials(scheme='Bearer', credentials=access_token)
await auth.verifier.verify_token(http_auth)
True
The problem is that jwt.decode
(jose
lib) doesn't expect client_id
in token and since aud
is not defined it skips validation.
i can't seem to find an audience (and the rest params) verifier.
it seems that only signature is verified
i see a decode
method that should do all that and get the needed information back here https://github.com/mpdavis/python-jose/blob/master/jose/jwt.py#L57
can this be used?
We're running an issue where the iat
claim (Issued At) in AWS Cognito is ~1 second into the future (on multiple machines and server configurations, synced with NTP).
Would it be helpful to maybe add a configurable time delta to verification to account for these slightly out of sync use cases?
I can create a PR for this, but I first wanted to check if this would be anything that could be incorporated.
Hello!
I'm trying to use cloudauth as a dependency injected value, and am having a bit of trouble getting it setup.
Basically, I have auth setup like:
def my_scoped_auth(conf: config.Config = config_dependency):
"""Get an auth scope dependency for DICOM reading."""
auth = Cognito(region=conf.cognito_region, userPoolId=conf.cognito_pool_id)
auth.scope_key = "scope"
auth.scope_name = "my_scope"
return auth
@app.get("/test", dependencies=[Depends(my_scoped_auth)])
def test_endpoint(
):
return Response("OK")
This doesn't work since the auth
is never actually called.
I've also tried other variations like:
async def my_scoped_auth(conf: config.Config = config_dependency):
"""Get an auth scope dependency for DICOM reading."""
auth = Cognito(region=conf.cognito_region, userPoolId=conf.cognito_pool_id)
auth.scope_key = "scope"
auth.scope_name = "my_scope"
return await auth()
But this fails since the call now no longer has context of the dependency tree.
There maybe something obvious here, but couldn't figure out how to get this working.
For some additional context, I'm trying to link this up so I can have my unit tests decoupled ala:
@pytest.fixture()
def client(test_config, cognito, backend_client):
"""Simple happy path client."""
app.dependency_overrides[main.get_config] = lambda: mock_config
app.dependency_overrides[main.my_scoped_auth] = lambda: mock_cognito
client = TestClient(app)
return client
So the usual globally scoped object doesn't work.
Thanks!
First of all, thanks for your work, easy and clear to use 😄
The issue I'm facing isn't related to repo itself, but on how to generate the Auth0 token to have all the needed information to use the methods properly.
For some endpoints that I'm implementing I'll just need to check if the token has the required scopes and for some others I'll need to use: current_user: Auth0Claims = Depends(auth.get_current_user)
. However I can't find a way to request to Auth0
a token with all of this information: username
and scopes
. I don't know if I'm misunderstanding some information/concepts or what is going wrong...
Would appreciate some information with the steps to follow. Thanks in advance!
I notice there is (not jet) a validation of the JWK token in your code.
So if you disable or delete a user from Cognito the tokens which have been assinged before are still valid if validating against your own /well-known/jwks.json url.
Is there a easy way to work around this? For now I check the token on the API end point get_user
so get the current status of the user.
Request: adding documentation of mocking auth for tests.
I tried:
"""tests/test_templates.py"""
from fastapi.testclient import TestClient
from tests import auth_with_mocked_auth
client = TestClient(auth_with_mocked_auth())
def test_create_template():
response = client.get("/templates/")
assert response.status_code == 200
"""tests/__init__.py"""
def auth_with_mocked_auth():
def override_auth_dependency():
return {
'iss': '<auth0 endoint>',
'sub': 'auth0|<auth0 id>',
'aud': [
'<endpoints>',
],
'iat': <...>,
'exp': <...>,
'azp': '<...>,
'scope': 'openid profile email read:current_user update:current_user_metadata',
'permissions': [<...>]
}
app.dependency_overrides[auth] = override_auth_dependency()
return app
Yet, getting 403 with details: "Not authenticated"
This took me a while to track down.
Reproduce with: python -c 'from fastapi_cloudauth.verification import *; print(JWKS.firebase("https://www.googleapis.com/robot/v1/metadata/x509/[email protected]"))'
If cryptography
is installed, this succeeds.
If it's not installed, it fails with the following traceback:
Traceback (most recent call last):
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/jose/backends/rsa_backend.py", line 152, in __init__
self._prepared_key = pyrsa.PublicKey.load_pkcs1(key)
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/key.py", line 124, in load_pkcs1
return method(keyfile)
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/key.py", line 327, in _load_pkcs1_pem
der = rsa.pem.load_pem(keyfile, 'RSA PUBLIC KEY')
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 101, in load_pem
pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)]
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 101, in <listcomp>
pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)]
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 75, in _pem_lines
raise ValueError('No PEM start marker "%r" found' % pem_start)
ValueError: No PEM start marker "b'-----BEGIN RSA PUBLIC KEY-----'" found
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/jose/backends/rsa_backend.py", line 155, in __init__
self._prepared_key = pyrsa.PublicKey.load_pkcs1_openssl_pem(key)
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/key.py", line 356, in load_pkcs1_openssl_pem
der = rsa.pem.load_pem(keyfile, 'PUBLIC KEY')
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 101, in load_pem
pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)]
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 101, in <listcomp>
pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)]
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 75, in _pem_lines
raise ValueError('No PEM start marker "%r" found' % pem_start)
ValueError: No PEM start marker "b'-----BEGIN PUBLIC KEY-----'" found
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/jose/backends/rsa_backend.py", line 158, in __init__
self._prepared_key = pyrsa.PrivateKey.load_pkcs1(key)
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/key.py", line 124, in load_pkcs1
return method(keyfile)
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/key.py", line 591, in _load_pkcs1_pem
der = rsa.pem.load_pem(keyfile, b'RSA PRIVATE KEY')
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 101, in load_pem
pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)]
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 101, in <listcomp>
pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)]
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 75, in _pem_lines
raise ValueError('No PEM start marker "%r" found' % pem_start)
ValueError: No PEM start marker "b'-----BEGIN RSA PRIVATE KEY-----'" found
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/jose/backends/rsa_backend.py", line 161, in __init__
der = pyrsa_pem.load_pem(key, b"PRIVATE KEY")
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 101, in load_pem
pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)]
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 101, in <listcomp>
pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)]
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/rsa/pem.py", line 75, in _pem_lines
raise ValueError('No PEM start marker "%r" found' % pem_start)
ValueError: No PEM start marker "b'-----BEGIN PRIVATE KEY-----'" found
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/fastapi_cloudauth/verification.py", line 70, in firebase
keys = {
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/fastapi_cloudauth/verification.py", line 71, in <dictcomp>
kid: jwk.construct(publickey, algorithm="RS256")
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/jose/jwk.py", line 79, in construct
return key_class(key_data, algorithm)
File "/home/adys/.cache/pypoetry/virtualenvs/ola-rJcPxiV6-py3.9/lib/python3.9/site-packages/jose/backends/rsa_backend.py", line 171, in __init__
raise JWKError(e)
jose.exceptions.JWKError: No PEM start marker "b'-----BEGIN PRIVATE KEY-----'" found
I'm too tired to keep debugging this and figure out why exactly this happens. At first glance it seems that jose has a rsa backend and a cryptography backend and silently falls back to the former if the latter is not installed. They likely don't support the same featureset. Looking at the traceback, I guess the native rsa backend doesn't support certificates… which, to be honest, could use a proper check with a NotImplementedError if that's the case.
I think you should change your dependency from python-jose
to python-jose[cryptography]
.
Using a straight copy-paste of your example application, I get this pickle error.
Traceback (most recent call last):
File "/Users/scott/.local/bin/uvicorn", line 10, in <module>
sys.exit(main())
File "/Users/scott/.local/lib/python3.8/site-packages/click/core.py", line 829, in __call__
return self.main(*args, **kwargs)
File "/Users/scott/.local/lib/python3.8/site-packages/click/core.py", line 782, in main
rv = self.invoke(ctx)
File "/Users/scott/.local/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/Users/scott/.local/lib/python3.8/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/Users/scott/.local/lib/python3.8/site-packages/uvicorn/main.py", line 355, in main
run(**kwargs)
File "/Users/scott/.local/lib/python3.8/site-packages/uvicorn/main.py", line 379, in run
server.run()
File "/Users/scott/.local/lib/python3.8/site-packages/uvicorn/main.py", line 407, in run
loop.run_until_complete(self.serve(sockets=sockets))
File "uvloop/loop.pyx", line 1456, in uvloop.loop.Loop.run_until_complete
File "/Users/scott/.local/lib/python3.8/site-packages/uvicorn/main.py", line 414, in serve
config.load()
File "/Users/scott/.local/lib/python3.8/site-packages/uvicorn/config.py", line 300, in load
self.loaded_app = import_from_string(self.app)
File "/Users/scott/.local/lib/python3.8/site-packages/uvicorn/importer.py", line 20, in import_from_string
module = importlib.import_module(module_str)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
File "<frozen importlib._bootstrap>", line 991, in _find_and_load
File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 783, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "./main.py", line 12, in <module>
@app.get("/", dependencies=[Depends(auth.scope("read:users"))])
File "/Users/scott/.local/lib/python3.8/site-packages/fastapi_cloudauth/base.py", line 83, in scope
obj = deepcopy(self)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 172, in deepcopy
y = _reconstruct(x, memo, *rv)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 270, in _reconstruct
state = deepcopy(state, memo)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 146, in deepcopy
y = copier(x, memo)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 230, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 146, in deepcopy
y = copier(x, memo)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 230, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 172, in deepcopy
y = _reconstruct(x, memo, *rv)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 270, in _reconstruct
state = deepcopy(state, memo)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 146, in deepcopy
y = copier(x, memo)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 230, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 172, in deepcopy
y = _reconstruct(x, memo, *rv)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 270, in _reconstruct
state = deepcopy(state, memo)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 146, in deepcopy
y = copier(x, memo)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 230, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 172, in deepcopy
y = _reconstruct(x, memo, *rv)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 270, in _reconstruct
state = deepcopy(state, memo)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 146, in deepcopy
y = copier(x, memo)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 230, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "/Users/scott/.pyenv/versions/3.8.3/lib/python3.8/copy.py", line 161, in deepcopy
rv = reductor(4)
TypeError: cannot pickle '_cffi_backend.FFI' object
python-jose
doesn't support x509 certificates without the extra install option (anymore? I not quite sure if it was a silent breaking change).
This breaks the FirebaseCurrentUser's JWKS generation because google gives x509 files for the public key.
the recommended setup on python-jose
is using cryptography
as the background, setup as following
pip install python-jose[cryptography]
but is sort of a debate I guess (acknowledging the fact that cryptography requires building and is not a small dependency)
At least it needs some documentation about it, so I would like to know whats good for this library.
get_current_user = CognitoCurrentUser( region=region, userPoolId=poolid, client_id=clientid )
Often, we would like to support multiple aws Cognito app clients for a single API.
Requesting a feature to support multiple app client ids for the aws Cognito objects.
Maybe something like
get_current_user = CognitoCurrentUser( region=region, userPoolId=poolid, client_id=[clientid1, clientid2] )
Using the authorization modal (in the docs) ...
id_token
and attempt to access the /users/
endpoint a JWTClaimsError
is caught (i.e. "No access_token provided to compare against at_hash claim.")
access_token
and attempt to access the /users/
endpoint the token_use
claim is flagged (because it is equal to "id").
What am I missing?
Hi guys, thanks for writing this implementation!
I'm currently trying to fit this one into our set-up but I run into an issue with auto_error=False
setting not being respected by the dependency injections inside fastapi_cloudauth. Fastapi-cloudauth builds on the fastapi HTTPBearer
dependency injection, which raises an HTTPException
when the credentials are not found in the headers. To prevent this exception, it supports the auto_error=False
option. We need this to support other authentication methods.
Our authentication set-up is based on this medium article to combine multiple types of authentication. To make this work, the "auto_error=False" is essential, to make sure none of the authentication methods block each other. (see example implementation below)
Proposed fix:
In base.py
, there are these dependency injections for HTTPBearer(), which currently don't pass the auto_error parameter:
fastapi-cloudauth/fastapi_cloudauth/base.py
Line 153 in 36d947f
fastapi-cloudauth/fastapi_cloudauth/base.py
Line 192 in 36d947f
These dependencies do support the auto_error
parameter, like: HTTPBearer(auto_error=self.auto_error)
. Possibly you'd want to set this up as a partial function in the constructor.
For reference: example implementation
This fails on an HTTPException from HTTPBearer when the OAuth headers are not passed - which unfortunately is the case when another authentication method is used..
api_key_query_dependency = APIKeyQuery(name=settings.api_key_name, auto_error=False)
api_key_header_dependency = APIKeyHeader(name=settings.api_key_name, auto_error=False)
api_key_cookie_dependency = APIKeyCookie(name=settings.api_key_name, auto_error=False)
cognito_auth_dependency = Cognito(region=settings.aws_region,
userPoolId=settings.aws_cognito_user_pool_id,
auto_error=False
).scope("users")
async def get_authorization(
api_key_query: str = Security(api_key_query_dependency),
api_key_header: str = Security(api_key_header_dependency),
api_key_cookie: str = Security(api_key_cookie_dependency),
cognito_auth: str = Depends(cognito_auth_dependency),
) -> Security:
if not cognito_auth \
or api_key_query == settings.api_key \
or api_key_header == settings.api_key \
or api_key_cookie == settings.api_key:
raise HTTPException(
status_code=HTTP_403_FORBIDDEN, detail="Could not validate credentials"
)
I am new to Auth0 and l would like to understand the use of this library. I followed the auth0 example; l can see the fastapi schema; and l went to Auth0 dashboard for the domain. And anytime l visit the endpoint, l get forbidden error. My questions is how do l perform below and where do l use them with your package?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.