TCatshoek / fastapi-nextauth-jwt

FastAPI Dependency to decode nextauth generated JWTs, for use in projects that mix nextjs/nextauth and fastapi.
MIT License
99 stars 7 forks source link

Invalid padding bytes Error #12

Closed cblberlin closed 1 month ago

cblberlin commented 1 month ago

Hi,

i tried to decode the jwt token from auth.js v5.0.0-beta.17 and nextjs 14 app router, i just keep getting Invalid padding bytes error

firstly i install the package fastapi-nextauth-jwt

then i extrat the token in an api router

import { NextResponse } from "next/server";
import { getToken } from "next-auth/jwt";
import { NextRequest } from "next/server";

const secret = process.env.AUTH_SECRET as string;

export const GET = async (req: NextRequest) => {
  try {
    if (!secret) {
      throw new Error("NEXTAUTH_SECRET is not set");
    }

    const token = await getToken({ 
      req, 
      secret: secret,
      raw: true,
      salt: "authjs.session-token"
    });

    console.log("Token from getToken:", token ? `${token.substring(0, 20)}...` : "No token");

    if (!token) {
      return new NextResponse("No raw token found", { status: 401 });
    }

    console.log("Attempting to connect to FastAPI server...");
    const response = await fetch("http://127.0.0.1:8000/test_decode", {
      headers: {
        Cookie: `authjs.session-token=${token}`
      },
      credentials: 'include'
    });

    console.log("FastAPI response status:", response.status);

    const responseText = await response.text();
    console.log("FastAPI response body:", responseText);

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}, message: ${responseText}`);
    }

    const result = JSON.parse(responseText);
    console.log("Decoded token:", result);

    return new NextResponse(JSON.stringify({
      fastapi_decoded: result,
    }), { status: 200 });
  } catch (error) {
    console.error("GET_ORDERS error details:", error);
    return new NextResponse(`Internal Server Error: ${error}`, { status: 500 });
  }
};

then my fastapi is like this

from fastapi import FastAPI, HTTPException, Request
from fastapi_nextauth_jwt import NextAuthJWT
import uvicorn

app = FastAPI()

SECRET_KEY = "my_hard_coded_secret"
COOKIE_NAME = "authjs.session-token"

next_auth_jwt = NextAuthJWT(
    secret=SECRET_KEY,
    cookie_name=COOKIE_NAME
)

@app.get("/test_decode")
async def test_decode(request: Request):
    print("Received request at /test_decode")
    print("Cookies:", request.cookies)
    try:
        decoded_token = next_auth_jwt(request)
        print("Token successfully decoded")
        print(f"Decoded token: {decoded_token}")
        return {"decoded_token": decoded_token}
    except Exception as e:
        print(f"Error occurred: {str(e)}")
        raise HTTPException(status_code=401, detail=str(e))

if __name__ == "__main__":
    print("Starting FastAPI server...")
    print(f"Secret key: {SECRET_KEY}")
    print(f"Cookie name: {COOKIE_NAME}")
    uvicorn.run(app, host="0.0.0.0", port=8000)

and in the fastapi terminal i got

Starting FastAPI server...
Secret key: my_hard_coded_secret
Cookie name: authjs.session-token
INFO:     Started server process [46231]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
Received request at /test_decode
Cookies: {'authjs.session-token': 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwia2lkIjoiOXJLdVBzOUV3WjdkZ3k2YTRDX09wckt1THgzeHEwWkluNC1YUDZHUUx3dUpuUkxjSGpjMHVKTy1GRElSbngzVWw3VHlIcGl1dWh5R2t4a0MzWFU0UGcifQ..zIkxK5JUdetnWwN5mo9F1A.FYVLYIpsdhfGAz9NN-uznIFg8V8sY6Yhu4l5y6UMhki8thO0WXupC4Mw4G7JlbGFiHjAcxE33FyO-bNwJjU7KTleqHFxkwaX9iH1q4o4m9DHa_MRd655DZHRaz2nMdh60y0R6o69kYqv6U0he9TEWDIEeb7pRZzZ7UY5keTqnPHn21XXkp-ouWDFgs5UbOxe9-CUZ4GuuOBwOPEKNomvqrx_Amv836vpoNtmUbw51rd-BJx8CHaSSX-KWKCuVNQRgF5Xma0m-m06MaYpj-o2lYqsaczHsRTTiyEI2ZLQJrxRgjUznlFxEN8Bhg-S1XJI79HspYa9pTEzf2qjokLfsg.62j9fpdi5-6AWMNwXwS5ZaM3DbWqJ2DTVieXBm4m_1o'}
Invalid padding bytes.
Error occurred: 
INFO:     127.0.0.1:56110 - "GET /test_decode HTTP/1.1" 401 Unauthorized

any idea how where do i get wrong?

TCatshoek commented 1 month ago

Hi @cblberlin,

If I'm not mistaken getToken gets the decrypted/decoded contents of the JWT, which you are then sending to fastapi, which tries to decode it again, which doesn't work because it already is.

Try directly copying the headers and cookies from your incoming request in your nextjs route handler, and sending those through to fastapi unmodified, I think that should work.

Also on the fastapi side, leave the cookie name default.

Let me know if that works!

cblberlin commented 1 month ago

Wouldn't it be more clear-cut to completely separate the frontend and backend? It seems a bit odd to use Next.js for handling authentificatioin while having part of the backend implemented with FastAPI

TCatshoek commented 1 month ago

That is possible too of course! I started this project because I already had a frontend using nextauth and a backend using fastapi, if you're starting something new from scratch you could set it up however you like and may not need this.

cblberlin commented 1 month ago

yes me too, i've implemented the authentification part using auth.js on early stage but later when i cooperate with my colleague (who use fastapi as backend who has more experience on db query) we find out the Authorization part in API calls being hard (cause we don't know how to decode the cookies in python backend) that's why i found out your library, right now we decided to seperate the frontend and backend entirely (re-write whole authentification part) to make it well clear-cut...luckly it's just on early stage so we don't need to re-write the whole part but only design a well-structured OpenAPI docs