Giter Club home page Giter Club logo

fastapi-auth0's People

Contributors

danielsanchezq avatar dorinclisu avatar jakobkogler avatar samedii avatar therealsupermario avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

fastapi-auth0's Issues

Obtaining the token thru front end thru SDK

Hey, great package. I followed your video guide. If I obtain a token for a user using the authorize button in docs, that works fine. But, if I obtain a token on the front end using the Auth0, that token ends up being malformed even when I provide the audience.

Do you know how the correct token can be obtained thru the javascript SDK?

JWKS request [question]

Hi @dorinclisu thank for the library, this is great and very straightforward!

I have a question/suggestion, I can see that the request for retrieving the JSON web key sets is hardcoded during the entity initialisation (

self.jwks: Dict = requests.get(f'https://{domain}/.well-known/jwks.json').json()
)

So, in my case, my tests suit is fully running locally with a signed token that I'm generating locally instead of making external requests to Auth0; also, for uncoupling the tests suit in case I have to move out of Auth0 in the future.

Currently I avoid the issue monkey patching the entity so it works but I think that could be easy if we can extract that specific pice of code out of the initialisation.

What do you think?

Thanks again!

Question regarding differences between this project and FastAPI Cloud Auth

I'm not sure if this is the proper place to ask, but here I go.

I'm new to auth0 and Fast API and was looking at the different plugins that are available. The main ones that I saw were this plugin and FastAPI Cloud Auth. If I'm not mistaken, I saw that you created an issue for that plugin back in December.

If you don't mind me asking, I was just curious what the advantage of your implementation compared to theirs is and what led to you building your own?

Thanks for your time and effort on this project!

Switch from python-jose to pyjwt

Is there a plan to migrate from python-jose to pyjwt? Python-jose isn't maintained any more and contains some known vulnerabilities.

I noticed that there was some effort done in #41 , but not sure what happened to it. As an intermediate solution, we could perhaps move to python-jose[cryptography] which is already recommended above the default python-jose (with Python backend)?

Creating a M2M-only check.

Is there a nifty way to create an option to only allow m2m clients to use a specific endpoint, or do you suggest just using the CustomAuth0User workflow and then checking the grant-type on each endpoint?

An extension to this question might be allowing only clients with a custom scopes or those which are m2m tokens.

Regards.

PyPi Package

First of all thank you for your work on this library, it is the best-integrated way to get Auth0 to work with FastAPI. Would you be interested in publishing this package on PyPi?

Secure only if using `auth.get_user` as a function parameter

When securing endpoint only by decorator dependencies, it doesn't secure it at all...

Here is the relevant code rip:

@app.get("/templates", response_model=Response[List[Template]], dependencies=[Depends(auth.implicit_scheme)])
def list_templates():
   data = get_static("templates.json")
   return Response(data=data)

I'm expecting to get 403 when I don't send any Authorization header, but i get 200: curl --location --request GET 'http://localhost:8000/templates'

Only when I use auth.get_user as a parameter for list_templates function like this:

@app.get("/templates", response_model=Response[List[Template]], dependencies=[Depends(auth.implicit_scheme)])
def list_templates(user: Auth0User = Security(auth.get_user, scopes=['read:users'])):
    data = get_static("templates.json")
    return Response(data=data)

I get 403 when not sending Authorization header.

So, am I missing something? or do I have to use user for authentication will invoke?

pydantic validation error without scope

I tried the simple example without the scoping:

from fastapi import FastAPI, Depends, Security
from fastapi_auth0 import Auth0, Auth0User

auth = Auth0(
    domain='...',
    api_audience='...',
)
app = FastAPI()


@app.get("/")
async def root():
    return {"message": "Hello World"}


@app.get("/secure", dependencies=[Depends(auth.implicit_scheme)])
def get_secure(user: Auth0User = Security(auth.get_user)):
    return {"message": f"{user}"}

and authenticated a user. But when I tried to execute the /secure endpoint, it returns

{
  "detail": "Error parsing Auth0User"
}

and the console error

Handled exception parsing Auth0User: "1 validation error for Auth0User
permissions
  Field required [type=missing, input_value={'iss': 'https://dev-aos6...CCDkOMHVc', 'scope': ''}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.1/v/missing"
Traceback (most recent call last):
  File "~/server/venv/lib/python3.9/site-packages/fastapi_auth0/auth.py", line 219, in get_user
    user = self.auth0_user_model(**payload)
  File "~/server/venv/lib/python3.9/site-packages/pydantic/main.py", line 159, in __init__
    __pydantic_self__.__pydantic_validator__.validate_python(data, self_instance=__pydantic_self__)
pydantic_core._pydantic_core.ValidationError: 1 validation error for Auth0User
permissions
  Field required [type=missing, input_value={'iss': 'https://dev-aos6...CCDkOMHVc', 'scope': ''}, input_type=dict]

Am I missing a piece of syntax?

[Question] Can I combine different auth methods ?

Thank you so much for your work so far. It was easy to add Auth0 support to my application.

I have been using it to verify the Bearer token and so far it has worked great. Now, I might have to add cookie support as well.

I was able to adapt your code to add a way to check the Cookie and decode/verify it and return the access_token to the get_user but the FastAPI router dependencies still expect the Bearer token so it fails. Or maybe I went about the wrong way.

Can you let me know if what I want to do is possible ?

# fastapi router

router = APIRouter(
    prefix="/api/user",
    dependencies=[Depends(auth0_object.authcode_scheme)],
    responses=default_responses,
)

# Added to your auth.py

from fastapi.security.api_key import APIKeyCookie

from config import auth0_settings
from utils.auth0_cookie_decryptor import validate_cookie

class AppSessionCookie(APIKeyCookie):
    async def __call__(self, request: Request):
        return await super().__call__(request)


def bearer_or_cookie_check(
    bearer_creds: HTTPAuthorizationCredentials = Security(
        Auth0HTTPBearer(auto_error=False)
    ),
    session_cookie: str = Security(
        AppSessionCookie(name="appSession", auto_error=False)
    ),
):
    if bearer_creds:
        return bearer_creds

    if session_cookie:
        try:
            decrypted_cookie = validate_cookie(
                jwe_secret=auth0_settings.session_secret.get_secret_value(),
                jwe_cookie_string=session_cookie,
            )
            if decrypted_cookie:
                creds = HTTPAuthorizationCredentials(
                    scheme=decrypted_cookie["token_type"],
                    credentials=decrypted_cookie["accessToken"],
                )
                return creds
        except Exception as error:
            logger.warning("Exception while decrypting cookie: %s", str(error.args))
            raise HTTPException(403, detail="Invalid session cookie")

    return None

# and changed the depends get_user

creds: Optional[HTTPAuthorizationCredentials] = Depends(
            bearer_or_cookie_check
        ),  # changed depends

I see that the authcode_scheme is also from the Auth0 class and that is where FastAPI checks and rejects if no bearer is found.

Should I just inherit and override the __call__ like you did for OAuth2ImplicitBearer ? This is only for Swagger so should be fine right ?

The weird thing is I can also see the appSession cookie in Swagger as well. I dunno where it's coming from.

Sorry for the "support" type issue but just wanted to see if I want can be done. Feel free to close it.

EDIT: I realise that the OAuth2AuthorizationCodeBearer is for use to get the access token directly (right ?) so will I lose that if I override the __call__ method ? The cookie will be set with the domain attribute from the frontend so I don't think I care about getting the cookie from Swagger.

I also understand that the actual verification is done in get_user so I can exclude dependencies from the router but I will lose the Swagger docs for auth. I would like to keep both.


UPDATE: Added more info about my goal.

I realised I might not have explained my intentions well.

Currently, I get an access_token from a React SPA and this library validates it.

We have another frontend client using Nextjs. That client doesn't have access to the token, instead it encrypts the access_token and the id_token in a cookie using a shared secret. The Next environment itself uses this cookie for Auth.

Now, this results in client requests being proxied via Next which itself requires duplicate proxy API endpoints in the frontend.

Because, the cookie can be sent across the same domain, we can call the backend and any available cookies can be sent with the request.

What I want to do (or kind of have done) is to read this cookie and decrypt it. Then I extract the access_token and pass that to the get_user function from this library.

The cookie is never modified or sent back to the client. The actual authentication is still done by this library. Any error with cookie validation will result in get_user dependency failure.

Authenticating user works from localhost, but not from domain for Single Page Application.

When I create the user for my FastAPI app via localhost the page redirects me to https://localhost/docs/oauth2-redirect#access_token={token}, and everything works well.

The issue is when I deploy my application on the server, then I get NGINX 404 error. I tried messing with application settings in auth0 but got no results, I am not exactly sure what is wrong here.

Any guidance or tips would be welcome.

PS. my application is using additional prefix path {service-template-python/} I am also using authentication within APIRouter

How to authenticate Implicit Grant SPA

How can I use the Implicit grant without using swagger?

I managed to get to the LogIn box and authenticate, however I need to accomplish this without swagger.

How can I do a POST request to mi API and send the implicit grant there?

Optional authentication

Is this already possible? Is it bad practice? If not, how difficult do you think it would it be to implement?

If you can point me in the right direction then I can try to create a PR

E.g. something along the lines of

@router.get("/secure", dependencies=[Depends(auth.implicit_scheme)])
def get_secure(
    user: Optional[Auth0User] = None
):
    return {"message": f"{user}"}

Function of `auth0_rule_namespace`?

Hey, thanks for working on this! The timing is amazing for me.

I've been trying to get to grips with the code for this module, and I'm just wondering what's the function of the auth0_rule_namespace constant? The only time it's used seems to be in the Auth0 user model, as an alias for email. Mostly for my own sanity I was wondering if you could clarify what this is for?

Thanks!

Joel

Client Credentials Scheme

I've been integrating this package into my application and had a question regarding schemes.

If I understand correctly, the purpose of the auth schemes is to interface with OpenAPI and allow a developer to be able to test the API and authenticate directly from the FastAPI docs section of our APIs. Is that correct?

If so, I tried reading through the source code and didn't see a client credentials (m2m) scheme. Do you have any advice on how I could implement the client credentials scheme for Auth0 so I can authenticate using my m2m client id and client secret from the docs?

Token avalid for another api audience gives misleading error message

If you create an access token for a different API audience, or different tenant, then obviously the authorization should fail.
However the error message is 401 "Malformed token".
This is quite misleading, normally when a token is malformed, it is because you just gave a random string, or because you forgot to copy-paste a few characters.

The error comes from:

unverified_header = jwt.get_unverified_header(token)
rsa_key = {}
for key in self.jwks['keys']:
if key['kid'] == unverified_header['kid']:
rsa_key = {
'kty': key['kty'],
'kid': key['kid'],
'use': key['use'],
'n': key['n'],
'e': key['e']
}
#break # TODO: do we still need to iterate all keys after we found a match?
if rsa_key:
payload = jwt.decode(
token,
rsa_key,
algorithms=self.algorithms,
audience=self.audience,
issuer=f'https://{self.domain}/'
)
else:
if self.auto_error:
raise jwt.JWTError

The kid is different (because of different api audience), and therefore the rsa_key is empty, and a general JWTError is raised.

Is it possible to give a better error message. Maybe something like "Token not authorized" or "Token has wrong audience" would be better suited.

not able to run

when tried to run this command : uvicorn example:app --port 8081
Error : urllib.error.URLError:
Any suggestions please

Change of license to Apache v2?

Hi @dorinclisu ,

I really like your work here and I would like to incorporate it into my solution, which is currently open-sourced under the Apache v2 license.

Since this would not be possible, if I use a package with GPL version 3 license, I was wondering whether you are open to change the license to Apache v2? Or do you have some specific objections to that?

Make namespace an environment variable

I don't see an issue template format and I haven't contributed much to OSS yet so forgive me if this is messy.

First, this is a great package! It worked very well for me, and I'd love to help make it even better.

I think it would make sense to set auth0_rule_namespace via environment (or through some other means, but environment is what seems simplest to me). I'd be happy to make a PR with the changes. This would allow users to set their own namespace for the rule in auth0. It would just change this line:

auth0_rule_namespace: str = 'https://github.com/dorinclisu/fastapi-auth0'

to be:
auth0_rule_namespace: str = os.getenv('AUTH0_RULE_NAMESPACE', 'https://github.com/dorinclisu/fastapi-auth0')

Do you think that'd work fine? If so, I'd be thrilled to make a PR for it (I know it's very small but I figure I'd start small).

Unable to access email inside accessToken

I am unable to access email using accessToken

Steps I have done:

  • Set 'Add email to access token' rule from Auth0 dashboard:
function addEmailToAccessToken(user, context, callback) {
    var namespace = 'namespace';
    context.accessToken[namespace + 'email'] = user.email;
    return callback(null, user, context);
}
  • Set 'openid profile email' permission for API
  • Set environment variable to matching namespace:
os.environ["AUTH0_RULE_NAMESPACE"] = "namespace"
  • Sign out and sign back in from SPA frontend to renew accessToken

I have also tried adding passing 'openid profile email' to route and Auth0 scopes to see if makes any difference at all. It didn't

auth.get_user still returns email=None

What am I doing wrong? Thanks in advance.

Get a lost of user roles?

Quite new to auth0 so really like your repo here. Is there any way to get all the roles, assigned to a user?

Is there any way to extend the class Auth0User in order to pass additional fields to the payload? (e.g. custom field)

class Auth0User(Auth0UserBase):
    roles: list[str] = Field(None, alias=f'{settings.auth0_rule_namespace}/roles')  # type: ignore [literal-required]

I would like to extend your class Auth0 with an additional roles field, which I have added to my JWT
The main goal is to be able to obtain this field from the JWT passed through the request

@app.get("/api/get_auth0_user")
def get_secure(user: Auth0User = Security(auth.get_user)):
    return {"message": f"{user}"}
## Here it would display id, permissions, email, and roles

Support for multiple audience

api_audience parameter only takes a single string. How can I initiate with support for multiple audience (validates from a list of audience, so multiple clients can connect)

Websocket Auth Support

The auth flow currently uses Auth0HTTPBearer, which depends on a Request instance (http), for Websockets, I think we need to use cookies to pass the token?

Auth0 `permissions` in `Security` dependency?

I'm just wondering if there's a nice way to required specific auth0 permissions in the Security(get_user) dependency, similar to how you can require scopes. We have an application which uses permissions heavily and I'm wondering if I've missed something here.

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.