K
Kinde13mo ago
mnewcomer

NextJS App Router v2 getAccessToken() and getToken()

Hello again! Loving Kinde (and can't wait for custom favicons....), but I've ran into a little bit of a desync between either my implementation or the kinde documentation. I have a backend that I want to send the user's JWT to. I figured I would use the serverside method getAccessToken(), but it 1) returns null on a logged in user (profile pic, name, email from getUser() went fine, and 2) even if I got the KindeAccessToken there are no methods to convert it to a JWT (althought the documentation suggests getAccessToken() -> Promise<string>. So, I was like, that's okay, I'll add the token on the client side api client with the kinde client methods from useKindeAuth, getToken seems to return string | null but I only get null still. Wondering why I can't seem to access the JWT even if it's stored in Application Cookies. Would love any help, very excited to finally get this integrated with the backend. P.S. other than this token stuff I love the next app router sdk. it's been super easy to use and has sped up my development enormously.
5 Replies
Oli - Kinde
Oli - Kinde13mo ago
Hey @mnewcomer, The getToken method should indeed return the JWT token for a logged in user. I am sure we can together get to the bottom of your issue. Are you able to let me know what version of the Kinde NextJS SDK you are using? We just released a new version of the Kinde NextSDK v2.0.12 that fixes a lot of known issues.
mnewcomer
mnewcomerOP13mo ago
Just upgraded to v2.0.12 from v2.0.11. Here's some more context:
"use client"

export const ClientProvider: React.FC<ClientProviderProps> = ({ children }) => {
const { getToken, getAccessToken, accessToken, user } =
useKindeBrowserClient()
// const { getToken, getAccessToken, accessToken, user } = useKindeAuth() // tried with both of useKindeAuth() + useKindeBrowserClient()
console.log(getAccessToken())
console.log(getToken())
console.log(accessToken)
console.log(user)

// ...
}
"use client"

export const ClientProvider: React.FC<ClientProviderProps> = ({ children }) => {
const { getToken, getAccessToken, accessToken, user } =
useKindeBrowserClient()
// const { getToken, getAccessToken, accessToken, user } = useKindeAuth() // tried with both of useKindeAuth() + useKindeBrowserClient()
console.log(getAccessToken())
console.log(getToken())
console.log(accessToken)
console.log(user)

// ...
}
This outputs (the "/" route is wrapped with this <ClientProvider/> wrapper):
Next.js 14.0.3 (turbo)
- Local: http://localhost:3000
- Environments: .env.local

Ready in 590ms
Compiling /page ...
Compiled /page in 5.6s
null
null
null
null
Next.js 14.0.3 (turbo)
- Local: http://localhost:3000
- Environments: .env.local

Ready in 590ms
Compiling /page ...
Compiled /page in 5.6s
null
null
null
null
^^ i am logged in here, my user information is available through the code below... On the server side of that route (which has all been working):
// app/(locked)/layout.tsx
const { isAuthenticated, getUser, getPermission, getAccessToken, getIdToken } =
getKindeServerSession()

export default async function LockedLayout({
children,
}: {
children: React.ReactNode
}) {
if (!(await isAuthenticated())) {
// correctly redirects, would love to move this to something else but it works
redirect("/login")
}
const perm = await getPermission("admin") // want to move this to the ClientProvider wrapper
const user = await getUser() // want to move this to the ClientProvider wrapper
const admin = perm?.isGranted || false

return (
<ClientProvider>
// ...
</ClientProvider>

// ...
}
// app/(locked)/layout.tsx
const { isAuthenticated, getUser, getPermission, getAccessToken, getIdToken } =
getKindeServerSession()

export default async function LockedLayout({
children,
}: {
children: React.ReactNode
}) {
if (!(await isAuthenticated())) {
// correctly redirects, would love to move this to something else but it works
redirect("/login")
}
const perm = await getPermission("admin") // want to move this to the ClientProvider wrapper
const user = await getUser() // want to move this to the ClientProvider wrapper
const admin = perm?.isGranted || false

return (
<ClientProvider>
// ...
</ClientProvider>

// ...
}
Which get's the user, isAuthenticated() and admin perm correctly
mnewcomer
mnewcomerOP13mo ago
For addition context, my Application Cookies look like this. Using the ClientProvider wrapper so next frontend can talk to a Rust axum backend. Currently have the access_token verification working with the public JWK (testing by just copy pasting access_token into postman Bearer Auth headers), just need this ClientProvider working so I can keep working on my authorized routes! More than happy to share axum middleware implementation if you guys happen to start working on a Rust SDK
No description
peteswah
peteswah13mo ago
You might need to do an isLoading check in the ClientProvider Here's an example on what I did for one of my Client component pages:
"use client";

import { Skeleton } from "@/components/ui/skeleton";
import { useKindeBrowserClient } from "@kinde-oss/kinde-auth-nextjs";

export const ClientComponentUser = () => {
const { user, isLoading, getToken } = useKindeBrowserClient();
console.log("getToken", getToken());

if (isLoading) return <Skeleton className="w-full h-[170px] mb-4" />;

return (
<div className="border border-slate-200 rounded-lg p-4 overflow-auto mb-4">
<pre className="text-sm text-slate-700">
<code>{JSON.stringify(user, null, 2)}</code>
</pre>
</div>
);
};
"use client";

import { Skeleton } from "@/components/ui/skeleton";
import { useKindeBrowserClient } from "@kinde-oss/kinde-auth-nextjs";

export const ClientComponentUser = () => {
const { user, isLoading, getToken } = useKindeBrowserClient();
console.log("getToken", getToken());

if (isLoading) return <Skeleton className="w-full h-[170px] mb-4" />;

return (
<div className="border border-slate-200 rounded-lg p-4 overflow-auto mb-4">
<pre className="text-sm text-slate-700">
<code>{JSON.stringify(user, null, 2)}</code>
</pre>
</div>
);
};
mnewcomer
mnewcomerOP13mo ago
Holy shit @peteswah, thank you so much
Want results from more Discord servers?
Add your server