Replies: 7 comments 20 replies
-
Hi @gex, The good news is that this is possible! The bad news is it's more work that it ideally should be. To share a Session Token / JSON Web Token across multiple sites with NextAuth.js you currently need to:
The difficulty with the current approach is that you need to specify the entire set of options for the To give you an idea, the cookies: {
sessionToken: {
name: process.env.NODE_ENV === 'production'
? `__Secure-next-auth.session-token`
: `next-auth.session-token`,
options: {
httpOnly: true,
sameSite: 'lax',
path: '/',
secure: process.env.NODE_ENV === 'production' ? true : false
}
},
} As long as all the sign up pages are hosted on the same subdomain as the API (e.g. I would like to make this easier, and then ultimately going further and support multi-domain sign in, as goals for the project. I would like to simplify this to top level option that is just Ultimately, I would also like to see us also support cross-domain sign in, and at that point we might replace |
Beta Was this translation helpful? Give feedback.
-
@iaincollins Hey, I'm in the process of stitching this together now. I just want to confirm that it takes:
async redirect({url, baseUrl}) {
const parsed = new URL(url, baseUrl);
if (parsed.hostname.endsWith(domain)) {
return parsed.toString();
}
return baseUrl;
}, And lastly, to limit the api endpoints to one app, is the best bet would be to create a custom Is this all correct? |
Beta Was this translation helpful? Give feedback.
-
Hey guys, coming up to this discussion I wonder about the "correct" or "aesthetic" way to manage that. If using a site for authentication my domains it is possible by a:
a. auth.domain.com just set or
a. generate JWT on auth.domain.com Solution for 1. is easy and like just configuration, number 2. needs more work. But which one is the right to choose from a "correct" or "aesthetic" point of view? |
Beta Was this translation helpful? Give feedback.
-
Well, I continued my working on that - "try" do write a NextAuth based AuthManager as separated nextjs app. Motivation for me is to split my application code in a monorepo and having there a standard authentication service as separate app. For the test I made following settings:
a. Application is running on http://app.acme.local:3000
To allow CORS the cookies have to be secured by https. a. Application is running on https://app.acme.local:3001
To allow cross-site cookie usage you need to set the CORS headers. const headers = [
"Accept", "Accept-Version", "Content-Length",
"Content-MD5", "Content-Type", "Date", "X-Api-Version",
"X-CSRF-Token", "X-Requested-With",
];
module.exports = {
reactStrictMode: true,
async headers() {
return [
{
source: "/api/(.*)",
headers: [
{ key: "Access-Control-Allow-Credentials", value: "true" },
{ key: "Access-Control-Allow-Origin", value: "https://app.acme.local:3001" },
{ key: "Access-Control-Allow-Methods", value: "GET,POST" },
{ key: "Access-Control-Allow-Headers", value: headers.join(", ") }
]
}
];
}
}; You need to set the credentials and cookies in `[...nextauth].ts Be aware of import NextAuth, { NextAuthOptions } from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials";
export const authOptions: NextAuthOptions = {
session: {
strategy: "jwt",
// Seconds - How long until an idle session expires and is no longer valid.
maxAge: 10,
},
providers: [
CredentialsProvider({
name: "Credentials",
credentials: {
username: { label: "Username", type: "text", placeholder: "jsmith" },
password: { label: "Password", type: "password" }
},
// any values will sign-in as jsmith
async authorize(credentials, req) {
const user = { id: 1, name: "J Smith", email: "jsmith@example.com" }
return user
}
})
],
theme: {
colorScheme: "dark",
},
cookies: {
sessionToken: {
name: `__Secure-next-auth.session-token`,
options: {
httpOnly: true,
sameSite: 'none',
path: '/',
secure: true,
}
},
callbackUrl: {
name: `__Secure-next-auth.callback-url`,
options: {
sameSite: "none",
path: "/",
secure: true,
},
},
csrfToken: {
name: `__Host-next-auth.csrf-token`,
options: {
httpOnly: true,
sameSite: "none",
path: "/",
secure: true,
},
},
pkceCodeVerifier: {
name: `__Secure-next-auth.pkce.code_verifier`,
options: {
httpOnly: true,
sameSite: "none",
path: "/",
secure: true,
},
},
state: {
name: `__Secure-next-auth.state`,
options: {
httpOnly: true,
sameSite: "none",
path: "/",
secure: true,
},
},
},
}
export default NextAuth(authOptions) Now you can login at auth.acme.local:4001 and use the token at app.acme.local:3001 Even that at app.acme.local is no useSession you may use Example from export default function ProtectedPage() {
const [content, setContent] = useState()
// Fetch content from protected route
useEffect(() => {
const fetchData = async () => {
const res = await fetch("https://auth.acme.local:4001/api/examples/protected", {mode: 'cors', credentials: 'include'})
const json = await res.json()
if (json.content) {
setContent(json.content)
} else if (json.error) {
setContent(json.error);
}
}
fetchData()
}, [])
return (
<Layout>
<h1>Protected Page</h1>
<p>
<strong>{content ?? "\u00a0"}</strong>
</p>
</Layout>
)
} Check out the video: NextAuthCorsDemo.mp4Now that the techniques are working - what would be the best workflow?
If user is not already logged in:
Is this a good way? Some better or more suggested ideas or proposals? Thanks for continuing the discussion @iaincollins @balazsorban44 : I can imagine that in conjunction with a monorepo this might be suitable for more developer? Cheers |
Beta Was this translation helpful? Give feedback.
-
Finally got this working. So if you have the following
You need to set the cookie with the domain set to Then the next challenge will be to make this work during local development. For example if you have the following:
Trying to set the cookie with the domain set to But his worked for me:
I have set the cookie with the domain set to either
|
Beta Was this translation helpful? Give feedback.
-
<!--
/* Font Definitions */
@font-face
{font-family:Wingdings;
panose-1:5 0 0 0 0 0 0 0 0 0;}
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
code
{mso-style-priority:99;
font-family:"Courier New";}
pre
{mso-style-priority:99;
mso-style-link:"HTML Preformatted Char";
margin:0in;
font-size:10.0pt;
font-family:"Courier New";}
span.HTMLPreformattedChar
{mso-style-name:"HTML Preformatted Char";
mso-style-priority:99;
mso-style-link:"HTML Preformatted";
font-family:"Courier New";}
.MsoChpDefault
{mso-style-type:export-only;}
@page WordSection1
{size:8.5in 11.0in;
margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
{page:WordSection1;}
/* List Definitions */
@list l0
{mso-list-id:316570696;
mso-list-template-ids:-1;}
@list l0:level1
{mso-level-number-format:bullet;
mso-level-text:\F0B7;
mso-level-tab-stop:.5in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l0:level2
{mso-level-number-format:bullet;
mso-level-text:o;
mso-level-tab-stop:1.0in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:"Courier New";
mso-bidi-font-family:"Times New Roman";}
@list l0:level3
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:1.5in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l0:level4
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:2.0in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l0:level5
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:2.5in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l0:level6
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:3.0in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l0:level7
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:3.5in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l0:level8
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:4.0in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l0:level9
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:4.5in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l1
{mso-list-id:385104921;
mso-list-template-ids:-1;}
@list l1:level1
{mso-level-number-format:bullet;
mso-level-text:\F0B7;
mso-level-tab-stop:.5in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l1:level2
{mso-level-number-format:bullet;
mso-level-text:o;
mso-level-tab-stop:1.0in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:"Courier New";
mso-bidi-font-family:"Times New Roman";}
@list l1:level3
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:1.5in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l1:level4
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:2.0in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l1:level5
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:2.5in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l1:level6
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:3.0in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l1:level7
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:3.5in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l1:level8
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:4.0in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l1:level9
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:4.5in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l2
{mso-list-id:1117411000;
mso-list-template-ids:-1;}
@list l2:level1
{mso-level-number-format:bullet;
mso-level-text:\F0B7;
mso-level-tab-stop:.5in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l2:level2
{mso-level-number-format:bullet;
mso-level-text:o;
mso-level-tab-stop:1.0in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:"Courier New";
mso-bidi-font-family:"Times New Roman";}
@list l2:level3
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:1.5in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l2:level4
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:2.0in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l2:level5
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:2.5in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l2:level6
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:3.0in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l2:level7
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:3.5in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l2:level8
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:4.0in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
@list l2:level9
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:4.5in;
mso-level-number-position:left;
text-indent:-.25in;
mso-ansi-font-size:10.0pt;
font-family:Wingdings;}
ol
{margin-bottom:0in;}
ul
{margin-bottom:0in;}
-->Hey Gab, do you have this working in a public repo? I’d love to check it out if you do! -Mitch From: Gab LabelleSent: Monday, February 26, 2024 3:03 PMTo: nextauthjs/next-authCc: Mitch Horacek; MentionSubject: Re: [nextauthjs/next-auth] use next-auth on a subdomain as a separated authentication service (Discussion #1299) Finally got this working. So if you have the followingapp.company.com (login here)subdomain.company.comcompany.comYou need to set the cookie with the domain set to company.com.Then the next challenge will be to make this work during local development.For example if you have the following:app.localhost (login here)subdomain.localhostlocalhostTrying to set the cookie with the domain set to localhost will not work.But his worked for me:app.company.localhost (login here)subdomain.company.localhostcompany.localhostI have set the cookie with the domain set to either company.com or company.localhost depending on where the app is running (deployed vs locally). Please note that I'm always using https even locally or else Azure doesn't allow me to redirect to a non https redirect URI if not precisely localhost (localhost OK but not app.company.localhost).NEXT_PUBLIC_APP_URL=https://app.company.localhost (env.local)ORNEXT_PUBLIC_APP_URL=https://app.company.com (when deployed)... function getCookieHostname() { const hostname = new URL(env.NEXT_PUBLIC_APP_URL).hostname; const [subDomain] = hostname.split("."); const cookieDomain = hostname.replace(`${subDomain}.`, ""); return cookieDomain;} ... const domain = getCookieHostname(); ...pages: { signIn: `${env.NEXT_PUBLIC_APP_URL}/login`,},cookies: { sessionToken: { name: `__Secure-next-auth.session-token`, options: { sameSite: "none", secure: true, httpOnly: true, path: "/", domain, }, }, callbackUrl: { name: `__Secure-next-auth.callback-url`, options: { sameSite: "none", secure: true, httpOnly: true, path: "/", domain, }, }, csrfToken: { name: `next-auth.csrf-token`, options: { sameSite: "none", secure: true, httpOnly: true, path: "/", domain, }, }, },—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you were mentioned.Message ID: ***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
<!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
.MsoChpDefault
{mso-style-type:export-only;}
@page WordSection1
{size:8.5in 11.0in;
margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
{page:WordSection1;}
-->No problem! Thanks for your detailed post nonetheless – it was very helpful! -Mitch From: Gab LabelleSent: Wednesday, February 28, 2024 4:28 PMTo: nextauthjs/next-authCc: Mitch Horacek; MentionSubject: Re: [nextauthjs/next-auth] use next-auth on a subdomain as a separated authentication service (Discussion #1299) Hey Gab, do you have this working in a public repo? I’d love to check it out if you do! -MitchThe repo is not public, I'm sorry.—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you were mentioned.Message ID: ***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
hello,
i found something similar in the faq but in my case the other website would use nextjs as well. when i add next-auth without creating the api route i get some warnings/error messages. so i'm wondering if it's doable at all.
there would be 3 applications in play:
the user would use the nextjs app with a jwt from the auth app and data from the api.
in theory i need the following steps:
i have not investigated all these steps deeply yet because i got that error message about the missing api route but is it possible to make something like this work with next-auth? can two applications share next-auth? in this case the majority of the backend code would be in the auth app and the majority of frontend code would be in the nextjs app.
thanks!
Beta Was this translation helpful? Give feedback.
All reactions