Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

401 ERROR - Cookie has wrong format #62

Closed
Residuum22 opened this issue Oct 6, 2021 · 8 comments
Closed

401 ERROR - Cookie has wrong format #62

Residuum22 opened this issue Oct 6, 2021 · 8 comments

Comments

@Residuum22
Copy link

Hi!

I think I have found a bug in the login with cookies. I always got 401 error, so I started to dig down in the script. Finally I have found the problem and the "hotfix" solution.
Well:
The byte array somewhere will be converted into string so in the cookie the b' * ' identifiers are remamining in the cookie and the jwt parser can not parse the data. For example:
Token (cookie):

b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJtbWFyayIsImV4cCI6MTYzMzUzMzU2OH0.NQzZOhaA0hyQBd8gLuLbs7zRaJfbgYLADwLJtPDEUWw'

If I cuted down the first two byte and the last byte the decode works like a charm.
Cutted token:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJtbWFyayIsImV4cCI6MTYzMzUzMzU2OH0.NQzZOhaA0hyQBd8gLuLbs7zRaJfbgYLADwLJtPDEUWw

Have you experienced this error?

@MushroomMaula
Copy link
Owner

This error is occuring because the cookie is expected to be a string not a byte array or bytes.
Can you share the code how you set the cookie?

@Residuum22
Copy link
Author

Here is the environment of the creation of the cookie:

@app.post("/login")
def login(request: Request, username: str = Form(...), password: str = Form(...)):
#def login(request: Request, form_data: OAuth2PasswordRequestForm = Depends()):
    # Select users from database
    #user = load_user(form_data.username)
    loginUser = select(members.c.username, members.c.password).where(
        members.c.username == username)
    result = engine.execute(loginUser)
    row = result.fetchone()
    logger.info("Post login user is: " + row.username)

    # Check exist of the username
    # if user is None:
    #     return templates.TemplateResponse("login.html", {"request": request, "error_status": "Didn't find any user with this username! Try again or register!"})

    # Check match of the password
    if row.password == password:

        access_token = manager.create_access_token(
            data={"sub":username}
        )
        logger.info("Token has been created!")
        response = RedirectResponse(
            url="/frontpage", status_code=status.HTTP_302_FOUND)

        manager.set_cookie(response, access_token)
        #logger.info("Cookie has been created!")

        # return {'access_token': access_token, 'token_type': 'bearer'}
        return response

    else:
        #raise InvalidCredentialsException
        return templates.TemplateResponse("login.html", {"request": request, "error_status": "Password isn't correct! Try again!"})

And here is the user loader:

@manager.user_loader()
def load_user(username: str):
    loginUser = select(members.c.username, members.c.password).where(
        members.c.username == username)
    result = engine.execute(loginUser)
    row = result.fetchone()
    if row:
        logger.info("Loaded user is: " + row.username)
        print("Loaded user is: " + row.username)
        return row.username
    else:
        logger.error("User not found")
        print("User not found")
        return None

@MushroomMaula
Copy link
Owner

MushroomMaula commented Oct 7, 2021

Honestly I have no idea why your code is not working.
What version of fastapi-login are you using?
Have you set the use_cookie=True argument and are you using the manager as a dependency?

This is the code I used to try if cookies are working as expected:
You can try for yourself if this works by opening 127.0.0.1:8000/login

from fastapi import FastAPI, Depends
from starlette.status import HTTP_302_FOUND
from starlette.requests import Request
from starlette.responses import HTMLResponse, RedirectResponse
from fastapi_login import LoginManager

DB = {"test-user@example.org": {"email": "test-user@example.org", "password": "hunter2"}}
app = FastAPI()
manager = LoginManager(secret="your-secret-key", token_url="/login", use_cookie=True)


@manager.user_loader()
def get_user(email: str):
    return DB[email]


@app.get('/login')
def login():
    """
    For testing purposes this automatically creates a access token and the redirects to /cookies
    """
    access_token = manager.create_access_token(
        data={'sub': 'test-user@example.org'}
    )
    print(f"Access token is: {access_token}")

    response = RedirectResponse(url="/cookies", status_code=HTTP_302_FOUND)
    manager.set_cookie(response, access_token)
    print(f"Response headers are: {response.headers}")

    print(f"Redirecting to '/cookies'")
    return response


@app.get('/cookies')
async def list_cookies(request: Request, user=Depends(manager)):
    """
    Returns a json response containing all cookies set in the request
    and tries to load the user from the token, if this fails a InvalidCredentialsException is returned
    """
    print('Authentication was successfull.')
    print(f'Authorization cookie: {request.cookies.get(manager.cookie_name)}')
    return {
        'cookies': request.cookies,
        'auth': {
            'successful': True,  # Otherwise a exception is returned
            'user': user
        }
    }


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app)

@MushroomMaula
Copy link
Owner

Did this help?

@Residuum22
Copy link
Author

Sorry for the late reply, but I had not too much time in the last few days.
Your code output:

{"cookies":{"access-token":"b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0LXVzZXJAZXhhbXBsZS5vcmciLCJleHAiOjE2MzM5NzAwNTB9.Xg60C82RSd4UtubpdmCtD10HeLEfioJLCVYRwvzy1sY'"},"auth":{"successful":true,"user":{"email":"test-user@example.org","password":"hunter2"}}}

I suspect if I am the only one, who having this problem, that there is something wrong with the wsl. Interesting.

@MushroomMaula
Copy link
Owner

Interestingly the access-token in your case still contains the b' * ', no matter how (i.e. browser, python requests or httpie) I cannot replicate that behaviour.
Do you mind sharing which browser you use or how you get the response, just in case other people have the same issue?

@Residuum22
Copy link
Author

I am using Edge chromium lastest build, but this issue also exist in Firefox. I will try it on my native linux machine tomorrow and I will reply back!

@MushroomMaula
Copy link
Owner

Thank you.
In just tried it inside a arch linux vm and it seemed to work for me just fine.
Can you also share the output of pip list from inside your virtualenv?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants