Search code examples
reactjsdjangoauthenticationclerk

Clerk jwt authentication


I have a React application that talks to a Django API and it uses a JWT token to authenticate requests. I wanna use Clerk to authenticate users on the frontend but I don't know how I'll get the JWT token to authenticate the requests to the backend API, can anyone help?


Solution

  • The following is what the front-end code would look like:

    import { useAuth } from "@clerk/clerk-react"
    
    function App() {
      const { getToken } = useAuth();
    
      const sendRequest = async (e) => {
        e.preventDefault()
        fetch(
          api_url,
          {
            method: 'GET',
            headers: { Authorization: `Bearer ${await getToken()}` },
          },
        )
          .then(response => response.json())
          .then(json => console.log(json))
          .catch(error => console.error(error));
      }
      ...
    }
    

    The following is an example of authentication on the back-end (using FastAPI).

    import requests
    import jwt
    from jwt.algorithms import RSAAlgorithm
    from fastapi import FastAPI, Request, HTTPException
    from fastapi.middleware.cors import CORSMiddleware
    
    
    @app.get("/")
    async def root(request: Request):
        auth_header = request.headers.get("Authorization")
    
        try:
            user_id = validate_token(auth_header)
        except AuthenticationException as e:
            raise HTTPException(status_code=400, detail=str(e))
    
        print(f"{user_id = }")
        return {"user": user_id}
    
    
    def validate_token(auth_header: str) -> str:
        """
        returns user_id if valid
        raises AuthenticationException otherwise
        """
        try:
            token = auth_header.split(" ")[1]
        except (AttributeError, KeyError):
            raise AuthenticationException("No authentication token provided")
    
        jwks = requests.get(
            "https://api.clerk.com/v1/jwks",
            headers={
                "Accept": "application/json",
                "Authorization": f"Bearer {CLERK_SECRET_KEY}",
            },
        ).json()
        public_key = RSAAlgorithm.from_jwk(jwks["keys"][0])
        try:
            payload = jwt.decode(
                token,
                public_key,
                algorithms=["RS256"],
                options={"verify_signature": True},
            )
        except jwt.ExpiredSignatureError:
            raise AuthenticationException("Token has expired.")
        except jwt.DecodeError:
            raise AuthenticationException("Token decode error.")
        except jwt.InvalidTokenError:
            raise AuthenticationException("Invalid token.")
        user_id = payload.get("sub")
        return user_id
    

    Make sure you replace CLERK_SECRET_KEY with your secret key.