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

Use of JWT callback to persist additional token info results in session being null. #33

Open
msardi23 opened this issue Jun 29, 2023 · 3 comments

Comments

@msardi23
Copy link

I am using the JWT callback to add additional information to the token like access_token, refresh_token and expires_at as outlined in the Auth.js docs here for the JWT callback and here for refresh token rotation.

While I have this working fine using Next.js 13 and Qwik, I have been struggling with Astro. As soon as I include logic in the JWT callback to enhance the token the session ends up being empty. When I remove the enhancement in the JWT callback the default session data is returned.

No errors are reported in the console. I am using the Azure AD provider.

export default {
  secret: import.meta.env.AUTH_SECRET,
  trustHost: true,
  providers: [
    AzureAd({
      clientId: import.meta.env.AZURE_CLIENT_ID,
      clientSecret: import.meta.env.AZURE_CLIENT_SECRET,
      tenantId: import.meta.env.AZURE_TENANT_ID,
      authorization: {
        params: {
          scope: "...removed...",
        },
      },
    }),
  ] as Provider[],

  callbacks: {
    async session({ session, token }) {
      if (token) {
        session.access_token = token.access_token;
      }
      return session;
    },
    async jwt({ token, user, account, profile, isNewUser }) {
      if (account) {
        token.access_token = account.access_token;
      }
      return token;
    },
  },
};

If I then check session via .../api/auth/session it returns an empty object.

If I comment out token.access_token = account.access_token; in the JWT callback the default session data is returned.

Same issue occurs using both JS and TS projects.

Please help 😀

@dvartdal
Copy link

dvartdal commented Dec 30, 2023

I have somehow a similar issue @msardi23 . However, for me, it works when only adding the account.access_token in my token, however, adding both the access_token and the refresh_token gives me the same error as you, where the getSession() returns null.

Not adding the refresh_token makes the getSession() return an existing session.

This is my code that works, and I have commented out the line adding the refresh_token to the token object for reference.

import AzureADB2C from '@auth/core/providers/azure-ad-b2c'
import { defineConfig } from 'auth-astro'

export default defineConfig({
	providers: [
		AzureADB2C({
			issuer: `https://${import.meta.env.AZUREADB2C_TENANT}.b2clogin.com/${
				import.meta.env.AZUREADB2C_TENANT_ID
			}/v2.0/`,
			wellKnown: `https://${import.meta.env.AZUREADB2C_TENANT}.b2clogin.com/${
				import.meta.env.AZUREADB2C_TENANT
			}.onmicrosoft.com/${import.meta.env.AZUREADB2C_POLICY}/v2.0/.well-known/openid-configuration`,
			authorization: {
				url: `https://${import.meta.env.AZUREADB2C_TENANT}.b2clogin.com/${
					import.meta.env.AZUREADB2C_TENANT
				}.onmicrosoft.com/${import.meta.env.AZUREADB2C_POLICY}/oauth2/v2.0/authorize`,
				params: {
					scope: `YOUR SCOPES`
				}
			},
			token: `https://${import.meta.env.AZUREADB2C_TENANT}.b2clogin.com/${
				import.meta.env.AZUREADB2C_TENANT
			}.onmicrosoft.com/${import.meta.env.AZUREADB2C_POLICY}/oauth2/v2.0/token`,
			clientId: import.meta.env.AZUREADB2C_CLIENT_ID,
			clientSecret: import.meta.env.AZUREADB2C_CLIENT_SECRET,
			allowDangerousEmailAccountLinking: true
		})
	],
	callbacks: {
		async signIn({ user, account, profile, email, credentials }) {
			if (profile) {
				if (user) {
					user.email = profile.email
				}
			}
			return true
		},
		async jwt({ token, user, account, profile }) {
			if (account && user) {
				const newToken = {
					accessToken: account.access_token,
					accessTokenExpires: Date.now() + account.expires_in! * 1000,
					// refreshToken: account.refresh_token,
					user
				}

				// console.log(newToken)
				return newToken
			} 

			// Return the current token if it's not expired or if there was no account object
			return token
		}
	}
})

For me, it seems that also adding a request token, maxes out the token size limit, or something. Because if I only add, for example: refreshToken: "refresh token", it works, and session is set.

From what I can see, from the Astro.request and the request cookies, the authcookie is not set when adding the full refreshToken, but is set when only adding accessToken.

The cookies remaining are: "authjs.csrf-token" and "authjs.callback-url" which for me, seems that something has happened when prosessing the extra data. The authjs cookie: "authjs.session-token" is missing.

When removing refreshToken so the session is not null anymore, the request header looks correct with the "authjs.session-token" cookie now in place.

I haven't calculated the size, but we might be hitting the browser cookie size limit (4kb). I know they have done something for this limitation for NextAuthJs:

nextauthjs/next-auth#3579 (comment)

Edit: Seemed to only work in dev. Built in prod or preview; session cookie is not set at all when doing changes in the callback as @msardi23 mentioned.

@nowaythatworked
Copy link
Owner

I just tested this on the latest astro, @auth/core and auth-astro version without any issues. Do you still have this problem?

@dvartdal
Copy link

I'm using my own version setting the refresh cookie in a separate cookie. However, I'll see if I can take a look at it and test!

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

3 participants