JWT Flow with OAuth #937

Closed
opened 2026-03-13 08:10:40 -05:00 by GiteaMirror · 7 comments
Owner

Originally created by @patrick91 on GitHub (Mar 28, 2025).

Is this suited for github?

  • Yes, this is suited for github

Hi there, I was asking about this on discord, and my understanding is that this is not possible yet; So I was wondering if we can implement support for JWTs when using Social providers, right now to use the JWT plugin you can request the token after logging by doing something like this:

const handleEmailLogin = async (e: React.FormEvent) => {
	e.preventDefault();
	const { data, error } = await authClient.signIn.email({
		email,
		password,
	});

	if (error) {
		setError(error.statusText);
	} else {
		const response = await fetch("/api/auth/token", {
			headers: {
				Authorization: `Bearer ${data.token}`,
			},
		});

		if (!response.ok) {
			setError("Failed to get token");

			return;
		}

		const json = await response.json();
		const token = json.token;
		// save token to local storage

		router.invalidate();
		router.navigate({ to: "/" });
	}
};

But this flow doesn't really work with OAuth, since there's a redirect in between.

Describe the solution you'd like

The way I was thinking this would work is this:

const handleGithubLogin = async () => {
	await authClient.signIn.social({
		provider: "github",
        redirectURI: "http://localhost:3000/github-login",
	});
};

This code would work as usual, but then we would be redirected to /github-login?code=abc and we'd need to handle that on our frontend, maybe with something like:

const handleGithubLogin = async () => {
    const { data, error } = await authClient.signIn.social({
		provider: "github",
        code: codeFromGetParams // similar to idToken
	});

    const response = await fetch("/api/auth/token", {
		headers: {
			Authorization: `Bearer ${data.token}`,
		},
	});

	if (!response.ok) {
		setError("Failed to get token");
	
		return;
	}
};

Describe alternatives you've considered

I can implement this flow by hand, but I wonder if it could be included by default with better auth? 😊

Additional context

Does this make sense? I'd be happy to help implement it in that case :D

Originally created by @patrick91 on GitHub (Mar 28, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### Is your feature request related to a problem? Please describe. Hi there, I was asking about this on discord, and my understanding is that this is not possible yet; So I was wondering if we can implement support for JWTs when using Social providers, right now to use the JWT plugin you can request the token after logging by doing something like this: ```ts const handleEmailLogin = async (e: React.FormEvent) => { e.preventDefault(); const { data, error } = await authClient.signIn.email({ email, password, }); if (error) { setError(error.statusText); } else { const response = await fetch("/api/auth/token", { headers: { Authorization: `Bearer ${data.token}`, }, }); if (!response.ok) { setError("Failed to get token"); return; } const json = await response.json(); const token = json.token; // save token to local storage router.invalidate(); router.navigate({ to: "/" }); } }; ``` But this flow doesn't really work with OAuth, since there's a redirect in between. ### Describe the solution you'd like The way I was thinking this would work is this: ```ts const handleGithubLogin = async () => { await authClient.signIn.social({ provider: "github", redirectURI: "http://localhost:3000/github-login", }); }; ``` This code would work as usual, but then we would be redirected to `/github-login?code=abc` and we'd need to handle that on our frontend, maybe with something like: ```ts const handleGithubLogin = async () => { const { data, error } = await authClient.signIn.social({ provider: "github", code: codeFromGetParams // similar to idToken }); const response = await fetch("/api/auth/token", { headers: { Authorization: `Bearer ${data.token}`, }, }); if (!response.ok) { setError("Failed to get token"); return; } }; ``` ### Describe alternatives you've considered I can implement this flow by hand, but I wonder if it could be included by default with better auth? 😊 ### Additional context Does this make sense? I'd be happy to help implement it in that case :D
Author
Owner

@kirill-dev-pro commented on GitHub (Mar 28, 2025):

I don't get, what is the issue?

@kirill-dev-pro commented on GitHub (Mar 28, 2025): I don't get, what is the issue?
Author
Owner

@patrick91 commented on GitHub (Mar 28, 2025):

@kirill-dev-pro sorry for not explaining properly, let me try again 😊

I have an SPA which needs to be able to authenticate users via GitHub (or any other OAuth provider) and I'd like to use JWTs instead of cookies.

The better auth server lives on another domain (like api.myapp.com). When I do this:

await authClient.signIn.social({ provider: "github" });

I get redirected to GitHub, which then redirects me to my backend, right? Then the backend creates the session and sets the cookies, but in my case I want to receive a JSON, and my understanding is I can only do that if I get redirected to my frontend app, send the code to the backend (which will create the session and return the data like when doing await authClient.signIn.email({ ... }))

Does this make more sense now?

I made a diagram to explain this flow:

sequenceDiagram
    participant User
    participant SPA as SPA (myapp.com)
    participant Backend as Backend API (api.myapp.com)
    participant GitHub as GitHub OAuth

    User->>SPA: Clicks "Sign in with GitHub"
    SPA->>Backend: Request OAuth URL
    Backend->>SPA: Returns OAuth URL with redirect to Backend
    SPA->>GitHub: Redirects to GitHub OAuth
    GitHub->>User: Presents authorization screen
    User->>GitHub: Approves authorization
    GitHub->>SPA: Redirects with auth code
    SPA->>Backend: Sends GitHub token to backend
    Backend->>GitHub: Exchanges code for access token
    Backend->>Backend: Creates user session
    Backend->>SPA: Returns session Data
    SPA->>Backend: with the session token we can call `/api/auth/token` to get the JWT
    SPA->>SPA: Stores JWT in memory/local storage
    SPA->>User: Shows authenticated state
@patrick91 commented on GitHub (Mar 28, 2025): @kirill-dev-pro sorry for not explaining properly, let me try again 😊 I have an SPA which needs to be able to authenticate users via GitHub (or any other OAuth provider) and I'd like to use JWTs instead of cookies. The better auth server lives on another domain (like api.myapp.com). When I do this: ```ts await authClient.signIn.social({ provider: "github" }); ``` I get redirected to GitHub, which then redirects me to my backend, right? Then the backend creates the session and sets the cookies, but in my case I want to receive a JSON, and my understanding is I can only do that if I get redirected to my frontend app, send the `code` to the backend (which will create the session and return the data like when doing `await authClient.signIn.email({ ... })`) Does this make more sense now? I made a diagram to explain this flow: ```mermaid sequenceDiagram participant User participant SPA as SPA (myapp.com) participant Backend as Backend API (api.myapp.com) participant GitHub as GitHub OAuth User->>SPA: Clicks "Sign in with GitHub" SPA->>Backend: Request OAuth URL Backend->>SPA: Returns OAuth URL with redirect to Backend SPA->>GitHub: Redirects to GitHub OAuth GitHub->>User: Presents authorization screen User->>GitHub: Approves authorization GitHub->>SPA: Redirects with auth code SPA->>Backend: Sends GitHub token to backend Backend->>GitHub: Exchanges code for access token Backend->>Backend: Creates user session Backend->>SPA: Returns session Data SPA->>Backend: with the session token we can call `/api/auth/token` to get the JWT SPA->>SPA: Stores JWT in memory/local storage SPA->>User: Shows authenticated state ```
Author
Owner

@CorySpeed commented on GitHub (Jun 17, 2025):

@patrick91 How did you end up getting around this?

@CorySpeed commented on GitHub (Jun 17, 2025): @patrick91 How did you end up getting around this?
Author
Owner

@patrick91 commented on GitHub (Jun 17, 2025):

@CorySpeed I don't really have any update unfortunately, I was just trying to understand how the library worked 😊

@patrick91 commented on GitHub (Jun 17, 2025): @CorySpeed I don't really have any update unfortunately, I was just trying to understand how the library worked 😊
Author
Owner

@dosubot[bot] commented on GitHub (Sep 16, 2025):

Hi, @patrick91. I'm Dosu, and I'm helping the better-auth team manage their backlog and am marking this issue as stale.

Issue Summary:

  • You requested support for JWT authentication flow with OAuth social providers, highlighting that the current JWT plugin only supports email login due to redirect handling limitations.
  • You proposed a frontend route to manage OAuth redirects and exchange authorization codes for tokens, including a detailed sequence diagram to explain the flow.
  • The maintainer asked for clarification, which you provided, but no solution or update has been implemented yet.
  • Another user expressed interest in any available workarounds, but you have not provided any updates since.

Next Steps:

  • Please let me know if this issue is still relevant with the latest version of better-auth by commenting here to keep the discussion open.
  • If I don’t hear back within 7 days, I will automatically close this issue.

Thank you for your understanding and contribution!

@dosubot[bot] commented on GitHub (Sep 16, 2025): Hi, @patrick91. I'm [Dosu](https://dosu.dev), and I'm helping the better-auth team manage their backlog and am marking this issue as stale. **Issue Summary:** - You requested support for JWT authentication flow with OAuth social providers, highlighting that the current JWT plugin only supports email login due to redirect handling limitations. - You proposed a frontend route to manage OAuth redirects and exchange authorization codes for tokens, including a detailed sequence diagram to explain the flow. - The maintainer asked for clarification, which you provided, but no solution or update has been implemented yet. - Another user expressed interest in any available workarounds, but you have not provided any updates since. **Next Steps:** - Please let me know if this issue is still relevant with the latest version of better-auth by commenting here to keep the discussion open. - If I don’t hear back within 7 days, I will automatically close this issue. Thank you for your understanding and contribution!
Author
Owner

@Nickersoft commented on GitHub (Sep 22, 2025):

Hey folks, I'm running into a similar issue here – my app runs on web and mobile, so for mobile (Tauri) I need to authenticate via JWT using my website's OAuth login (Google). My app currently links out to the web version, then is supposed to pass the JWT post-auth back to the app via a deeplink.

That said, it's tricky because, looking at the docs, it seems like:

  1. The bearer plugin allows you to retrieve session info via bearer auth, however there's no way to get the auth token if you use OAuth (the docs just use an email login example), and as you pointed out @patrick91, with the redirect you can't easily nab the token via the onSuccess callback.
  2. The JWT plugin makes it easy to generate JWTs using getToken(), but you can't use them via bearer auth to get session info.

I'm a bit at a loss here – seems like this would be a common-enough use case that BetterAuth would support it :/

@Nickersoft commented on GitHub (Sep 22, 2025): Hey folks, I'm running into a similar issue here – my app runs on web and mobile, so for mobile (Tauri) I need to authenticate via JWT using my website's OAuth login (Google). My app currently links out to the web version, then is supposed to pass the JWT post-auth back to the app via a deeplink. That said, it's tricky because, looking at the docs, it seems like: 1. The **bearer** plugin allows you to retrieve session info via bearer auth, _however_ there's no way to get the auth token if you use OAuth (the docs just use an email login example), and as you pointed out @patrick91, with the redirect you can't easily nab the token via the onSuccess callback. 2. The **JWT** plugin makes it easy to _generate_ JWTs using `getToken()`, but you can't use them via bearer auth to get session info. I'm a bit at a loss here – seems like this would be a common-enough use case that BetterAuth would support it :/
Author
Owner

@dosubot[bot] commented on GitHub (Dec 22, 2025):

Hi, @patrick91. I'm Dosu, and I'm helping the better-auth team manage their backlog and am marking this issue as stale.

Issue Summary:

  • You requested support for JWT token retrieval in OAuth social login flows, as the current better-auth JWT plugin only supports email/password login.
  • You proposed a frontend-managed flow exchanging the OAuth authorization code for a JWT token, including a detailed sequence diagram.
  • Maintainers asked for clarification, which you provided, but no solution has been implemented yet.
  • Other users, like Nickersoft, have expressed similar needs for JWT support with OAuth, indicating this is a common unaddressed use case.

Next Steps:

  • Please let me know if this issue is still relevant to the latest version of better-auth by commenting here to keep the discussion open.
  • If I do not hear back within 7 days, I will automatically close this issue.

Thank you for your understanding and contribution!

@dosubot[bot] commented on GitHub (Dec 22, 2025): Hi, @patrick91. I'm [Dosu](https://dosu.dev), and I'm helping the better-auth team manage their backlog and am marking this issue as stale. **Issue Summary:** - You requested support for JWT token retrieval in OAuth social login flows, as the current better-auth JWT plugin only supports email/password login. - You proposed a frontend-managed flow exchanging the OAuth authorization code for a JWT token, including a detailed sequence diagram. - Maintainers asked for clarification, which you provided, but no solution has been implemented yet. - Other users, like Nickersoft, have expressed similar needs for JWT support with OAuth, indicating this is a common unaddressed use case. **Next Steps:** - Please let me know if this issue is still relevant to the latest version of better-auth by commenting here to keep the discussion open. - If I do not hear back within 7 days, I will automatically close this issue. Thank you for your understanding and contribution!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#937