Next-Auth with Provider.Credentials: How to implement when API is already returning a JWT Token?
Asked Answered
E

2

15
  • I have a NextJS page where I try to implement Next-Auth.
  • I use credentials to login to my Rails API.
  • My API is returning (already) a JWT-Token. (so NextAuth must not create it)

How to implement the Provider.Credentials for [...nextauth].js in that case?

Flow "Diagram" Next request ---> Next API (with Next-Auth) ---> Rails API (returning Token)

At the momemt I have these options:

 providers: [
    CredentialsProvider({
      name: 'Email',
      credentials: {
        email: { label: "Email", type: "email", placeholder: "[email protected]" },
        password: {  label: "Passwort", type: "password" }
      },
      async authorize(credentials) {

        // The 'url' is pointing to a Rails API endpoint which returns a JWT Token
        const url = `${process.env.NEXT_PUBLIC_API_URL}/auth/login`;

        const res = await fetch(url, {
          method: 'POST',
          body: JSON.stringify(credentials),
          headers: {
            "Content-Type": "application/json" }
        })
        const user = await res.json()

        // If no error and we have user data, return it
        if (res.ok && user) {
          // I SAW EXAMPLES RETURNING {"email": "[email protected]"}
          return user // MY CONTENT {token: 'eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo0LCJyb2xl…0.OAGiwjj9O_NsH02lIjA2D4HYZkmTQ3_SqtKcVgaIul0'}

        }
        // Return null if user data could not be retrieved
        return null
      }
    })
  ]
}

A session_token is set in the browser, but that content is something (random?) what I dont have set. Where does this content come from if not from my token?

My Rails API Token Content:

{
  "user_id": 4,
  "roles": [
    "user"
  ],
  "exp": 1631096219
}

Next-Auth API Token Content:

{
  "iat": 1631009819,
  "exp": 1633601819
}

Do I have to decode my API token and reassamble that within the Provider.Credentials function?

I implement Next-Auth to provide more Authentications like Twitter and Co, but as well to make use of "useSession" instead of building everything of my own (Wont reinventing the wheel).

Evilminded answered 7/9, 2021 at 10:23 Comment(1)
Did you find a solution for this eventually? I too am working with an external api. I want to sync the expiry time of the tokens.Loupe
M
12

Add Callbacks.

    export default NextAuth({
      providers: [
        CredentialsProvider({
          name: "Email",
          credentials: {
            email: {
              label: "Email",
              type: "email",
              placeholder: "[email protected]",
            },
            password: { label: "Passwort", type: "password" },
          },
          async authorize(credentials) {
            // The 'url' is pointing to a Rails API endpoint which returns a JWT Token
            const url = `${process.env.NEXT_PUBLIC_API_URL}/auth/login`;
    
            const res = await fetch(url, {
              method: "POST",
              body: JSON.stringify(credentials),
              headers: {
                "Content-Type": "application/json",
              },
            });
            const user = await res.json();
    
            // If no error and we have user data, return it
            if (res.ok && user) {
              // I SAW EXAMPLES RETURNING {"email": "[email protected]"}
              return user; // MY CONTENT {token: 'eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo0LCJyb2xl…0.OAGiwjj9O_NsH02lIjA2D4HYZkmTQ3_SqtKcVgaIul0'}
            }
            // Return null if user data could not be retrieved
            return null;
          },
        }),
      ],
    
      callbacks: {
        async jwt({ token, user, account, isNewUser }) {// This user return by provider {} as you mentioned above MY CONTENT {token:}
          if (user) {
            if (user.token) {
              token = { accessToken: user.token };
            }
          }
          return token;
        },
    
        // That token store in session
        async session({ session, token }) { // this token return above jwt()
          session.accessToken = token.accessToken;
          //if you want to add user details info
          session.user = { name: "name", email: "email" };//this user info get via API call or decode token. Anything you want you can add
          return session;
        },
      },
    });
Magenmagena answered 11/10, 2021 at 18:17 Comment(4)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Uda
How can I read the cookie to use the JWT in further api calls?Thromboplastic
@Thromboplastic You can access session import { useSession } from 'next-auth/react'; <code> const {status, data}= useSession(); </code>Magenmagena
@shafiulislam is it safe to save your JWT access token inside session?Knesset
B
0

So the user that you return from the credentials authorize function will get stored in the JWT (JSON Web Token - which is passed around with all authenticated requests) which is a hashed/encoded (not encrypted by default!) version of the object.

You can use https://jwt.io to debug and see whats in your JWT. You paste into that site's debugger field your eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo0LCJyb2xl... value and it'll show you the { iat: 49835898: sub: 47897: email: '[email protected]' }, etc. value.

jwt.io example

If your rails API is returning a JWT to you in that fetch call in the authorize function, you can use a library like jwt-decode to decode it right there, and append any values from it which you would like to "persist" in your application to the user object you're returning from the authorize function in next-auth.

Bootless answered 18/9, 2021 at 23:49 Comment(2)
How is the other way around? could/should requests against the API (to fetch data) call the API with the old (origin) token or with the NextAuth generated JWT-token? The NextAuth one would not be accepted by the API-Server, right?Evilminded
Yeah so it depends on what you mean by API exactly. Are these API routes from next.js? Then the next-auth original jwt. Is it an API from your rails application? Then the rails jwt. Now I'm no oauth expert, but there doesn't seem to be any further identifying information in the rails jwt other than your userId. So I'd be curious if a custom JWT you create out of a combination of next-auth info and rails jwt info would work for both?Bootless

© 2022 - 2024 — McMap. All rights reserved.