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

Swagger UI Authorize doesn not find the correct OAuth2 Endpoint #230

Open
swoKorbi opened this issue Nov 25, 2024 · 3 comments
Open

Swagger UI Authorize doesn not find the correct OAuth2 Endpoint #230

swoKorbi opened this issue Nov 25, 2024 · 3 comments

Comments

@swoKorbi
Copy link

Describe the bug
I do have OAuth2 authentication implemented in my API.
After migrating to cadwyn versioning, the authorization through the Authorize button at the top of the swagger UI does not work anymore.
the API response I get is 404 NotFound on the /auth/login endpoint.
If I use the endpoint manually from the Swagger docs, I can sucessfully authorize against the endpoint and get back my JWT token.

I suspect, the endpoint doesn't get the proper API version header to use the correct authentication endpoint

To Reproduce
Steps to reproduce the behavior:

  1. Tried to login via Swagger Authorize button. I can log those header end get following API response:
DEBUG:rest_api_skeleton.app:Request headers: Headers({'host': 'localhost:1002', 'connection': 'keep-alive', 'content-length': '67', 'sec-ch-ua-platform': '"Windows"', 'authorization': 'Basic Og==', 'sec-ch-ua': '"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"', 'sec-ch-ua-mobile': '?0', 'x-requested-with': 'XMLHttpRequest', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'content-type': 'application/x-www-form-urlencoded', 'origin': 'http://localhost:1002', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'http://localhost:1002/docs?version=2024-11-20', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7', 'cookie': '_pk_id.1.1fff=2c6395af1ba573a7.1717565861.'})
INFO:     127.0.0.1:64457 - "POST /auth/login HTTP/1.1" 404 Not Found
  1. Manual login via endpoint from swagger UI:
DEBUG:rest_api_skeleton.app:Request headers: Headers({'host': 'localhost:1002', 'connection': 'keep-alive', 'content-length': '112', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36', 'accept': 'application/json', 'x-api-version': '2024-11-20', 'content-type': 'application/x-www-form-urlencoded', 'sec-ch-ua': '"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"', 'sec-ch-ua-mobile': '?0', 'origin': 'http://localhost:1002', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'http://localhost:1002/docs?version=2024-11-20', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7', 'cookie': '_pk_id.1.1fff=2c6395af1ba573a7.1717565861.'})
INFO:     127.0.0.1:64458 - "POST /auth/login HTTP/1.1" 200 OK

Expected behavior
The Authroize button in the swagger UI should send the appropriate x-api-version header to use OAuth2 authentication

@zmievsa
Copy link
Owner

zmievsa commented Nov 25, 2024

Thanks for reporting this! Can I ask you to provide a code snippet that allows me to reproduce the bug?

@swoKorbi
Copy link
Author

Thanks for the quick answer:

Here is a minimal working example:

import cadwyn
import fastapi
import pydantic
import fastapi.security
import datetime
import jwt
import typing
import uvicorn


class JWTToken(pydantic.BaseModel):
    access_token: str
    token_type: str

class User(pydantic.BaseModel):
    name: str

versions = cadwyn.VersionBundle(
    cadwyn.HeadVersion(),
    cadwyn.Version("2024-11-20"),
)

oauth_router = cadwyn.VersionedAPIRouter(prefix="")
oauth2_scheme = fastapi.security.OAuth2PasswordBearer(tokenUrl="/auth/login")

@oauth_router.post("/login")
async def login(
        form_data: fastapi.security.OAuth2PasswordRequestForm = fastapi.Depends(),
    ) -> JWTToken:
    user =  form_data.username == 'username' and form_data.password == 'password'
    if not user:
        raise fastapi.HTTPException(
            status_code=400, detail="Invalid authentication credentials"
        )

    timezone = datetime.timezone(datetime.timedelta(hours=2))
    expire = datetime.datetime.now(tz=timezone) + datetime.timedelta(
        minutes=60
    )
    data_to_encode = {"sub": form_data.username}
    data_to_encode.update({"exp": expire})
    access_token = jwt.encode(data_to_encode, 'SOME_SECRET_KEY', algorithm='HS256')
    return JWTToken(access_token=access_token, token_type="bearer")

async def get_current_user(token: str) -> typing.Optional[User]:
        payload = jwt.decode(token, 'SOME_SECRET_KEY', algorithms=['HS256'])
        username: str = payload.get("sub")
        return User(name=username)

async def get_current_active_user(token: str = fastapi.Depends(oauth2_scheme)) -> User:
    user = await get_current_user(token)
    if user is None:
        raise fastapi.HTTPException(
            status_code=400, detail="Invalid authentication credentials"
        )
    return user

@oauth_router.get("/verify")
def verify(_=fastapi.Depends(get_current_active_user)) -> bool:
    return True



app = cadwyn.Cadwyn(
    versions=versions,
)

app.generate_and_include_versioned_routers(oauth_router)


if __name__ == '__main__':
    uvicorn.run(app, host="0.0.0.0", port=8003)

@zmievsa
Copy link
Owner

zmievsa commented Nov 25, 2024

Nice example! I'll try to handle this today!

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