Getting session from Bearer token does not work

Hey, for some reason I can't get authenticating with the Bearer token to work. According to the docs it should be enough to call this, with the authorization header containing the bearer token.
const session = await auth.api.getSession({
headers: req.headers
});
const session = await auth.api.getSession({
headers: req.headers
});
However this does not return any session. I am getting the Bearer token from the set-auth-jwtheader. Am I missing something? EDIT: Looking deeper into this, the authorization header is definitely received by better-auth but then never converted to the cookie for some reason
25 Replies
dignmg
dignmg3mo ago
I have the same issue. I posted a question last week. Here is the link so we can resolve together! https://discord.com/channels/1288403910284935179/1377873006553989120 I am starting to think these two plugins are independent of each other. We have to write logic in our backend api to authenticate the token in the header. Then tie it to a user. But as mentioned I posted this question last week so not 100% sure
Gigadroid
GigadroidOP3mo ago
Yeah it's really weird, indeed seems like these are not working together like they should compared to what the docs are saying
dignmg
dignmg3mo ago
Also currently no luck in getting a direct answer
Gigadroid
GigadroidOP3mo ago
@Ping maybe you are able to help out here :/ Okay so auth works when using the token from 'set-auth-token' NOT when using 'set-auth-jwt'. So this would just need the bearer plugin. As far as I can tell, the token from 'set-auth-jwt' would need to be manually validated, doesn't seem like this is already implemented somewhere in the plugin. This whole setup seems very confusing and the docs are misleading
dignmg
dignmg3mo ago
Yes 100% that is my findings as well.
Aboud
Aboud3mo ago
Running into the same issue...
dignmg
dignmg3mo ago
@Gigadroid are you trying to use jwt or the session token?
Gigadroid
GigadroidOP3mo ago
Tried both, for my use case the JWT made more sense, so I implemented the verification of it myself
dignmg
dignmg3mo ago
That is what I did as well so far working.
tormentor
tormentor3mo ago
You have to take care of how your fetchOption works. Better-with uses particular fetchOption method to fetch your jwt. If you don’t use JWT plugin and don’t have jwt related table in your database, you can’t get the jwt token
dignmg
dignmg3mo ago
I do use the jwt plugin and all the database tables are there
tormentor
tormentor3mo ago
Client | Better Auth
Better Auth client library for authentication.
GreggOD
GreggOD3mo ago
To be honest I gave up on this getSession method cause its not explained well enough. It doesn't behave as you would expect. I ended up just fetching the session from the DB using my DB directly and avoided this pain.
highzenburger
highzenburger3w ago
This is such a headache.
Ping
Ping3w ago
Hey guys, sorry for taking so long to respond.. somehow missed this. Hmm, let me check something The JWT token is different to a bearer token
Ping
Ping3w ago
For example:
No description
highzenburger
highzenburger3w ago
Could you explain or give a snippet of how it should be used ? If my understanding is right, there's no way to disable session based cookies for better-auth (BA). You can add the plugins to your backend jwt() & bearer() as along as the frontend replies with the Authorization header set to Bearer + JWT token from "set-auth-token" header you're good to hit auth api endpoint "app.all("/api/auth/*", toNodeHandler(auth));" and also if you do
const session = await auth.api.getSession({
headers: fromNodeHeaders(req.headers),
});
const session = await auth.api.getSession({
headers: fromNodeHeaders(req.headers),
});
It'll verify the token?
Ping
Ping3w ago
Not sure I fully understand you. You can use the bearer token to make requests to the auth server via:
const res = await authClient.getSession({
fetchOptions: {
auth: {
type: "Bearer",
token: () => bearerToken,
},
},
});
const res = await authClient.getSession({
fetchOptions: {
auth: {
type: "Bearer",
token: () => bearerToken,
},
},
});
You can't use JWT to hit endpoints, the JWT plugin simply gives you the jwt token and allows you to grab user data out of it, or alternatively verifiy a JWT by using something like the jose library and then providing it the JWKS data from the /api/auth/jwks endpoint (https://www.better-auth.com/docs/plugins/jwt#example-using-jose-with-remote-jwks) Those are the two primary things the JWT plugin does. Gives you JWT, and allows you to verufy verify a given JWT token via JWKS endpoint.
JWT | Better Auth
Authenticate users with JWT tokens in services that can't use the session
spike
spike2w ago
Anyone get this working? seems like using the client is counter productive for anything that needs Bearer Token.
Timur
Timur2w ago
What are you trying to achieve?
spike
spike2w ago
Clearly not in the happy path but having an issue with the betterauth client and bearer tokens. Building a tauri app and trying to get oauth implemented with convex. I can login with github and get an ott that gets passed back to the app with universal link. in the app we hit the cross-domain/one-time-token/verify endpoint and get a token and can verify there is a user and a session. If we curl the get-session endpoint with the bearer auth token we have a session no issues. the getsession() doesnt work though as others have mentioned
Timur
Timur2w ago
So curling works but getSession doesn't. Have you tried what Ping said? I.e.
const res = await authClient.getSession({
fetchOptions: {
auth: {
type: "Bearer",
token: () => bearerToken,
},
},
});
const res = await authClient.getSession({
fetchOptions: {
auth: {
type: "Bearer",
token: () => bearerToken,
},
},
});
and how does the request headers look like when you have the setup above?
spike
spike2w ago
yea that doesnt work, this does though.
const bearerPlugin: BetterFetchPlugin = {
id: "bearer",
name: "Bearer",
hooks: {
async onRequest({ request }) {
const token = await keychainStorage.getItem(BEARER_TOKEN_KEY);
if (token) {
request.headers = {
...request.headers,
Authorization: `Bearer ${token}`,
};
} else if (request.headers?.Authorization) {
// ensure we don't send a stale header
const { Authorization, ...rest } = request.headers as any;
request.headers = rest;
}
},

// Optional: capture rotating tokens from responses
async onSuccess({ response }) {
const next = response.headers.get("set-auth-token");
if (next) {
await storeBearerToken(next);
// 2) Force get-session to refetch with the new token
authClient.$store.notify("$sessionSignal");
}
},
},
};
const bearerPlugin: BetterFetchPlugin = {
id: "bearer",
name: "Bearer",
hooks: {
async onRequest({ request }) {
const token = await keychainStorage.getItem(BEARER_TOKEN_KEY);
if (token) {
request.headers = {
...request.headers,
Authorization: `Bearer ${token}`,
};
} else if (request.headers?.Authorization) {
// ensure we don't send a stale header
const { Authorization, ...rest } = request.headers as any;
request.headers = rest;
}
},

// Optional: capture rotating tokens from responses
async onSuccess({ response }) {
const next = response.headers.get("set-auth-token");
if (next) {
await storeBearerToken(next);
// 2) Force get-session to refetch with the new token
authClient.$store.notify("$sessionSignal");
}
},
},
};
as far as i can see nothing ever consumes fetchOptions.auth in the client wrote a mini fetch plugin for the client that seems to fix things
Johnny
Johnny7d ago
Hey @spike, were you able to get this approach working with Tauri?

Did you find this page helpful?