-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
Magic Passcode #709
Comments
Also experience the same user experience issue - another way to solve this would be to handle email auth the same way https://magic.link/ or Vercel do. Rather than opening a new session, the link authenticates the original session. |
@glenames I thought about this. I guess I should take a deeper look into that. |
@alex-cory Its not possible with the current email auth implementation - its a suggested alternate feature request I guess. I think it's a fair bit trickier to implement because it would require a subscription to the database from the client requesting access. |
@glenames @iaincollins How does this flow look? Also, what is the recommended way of adding the jwt or session token or csrf token to the frontend. I'm not quite sure how next-auth is setting these on the frontend so when calling
I'd be interested in helping put a PR together for this. |
Hi there! It looks like this issue hasn't had any activity for a while. It will be closed if no further activity occurs. If you think your issue is still relevant, feel free to comment on it to keep it open. (Read more at #912) Thanks! |
keep alive |
Hi there! It looks like this issue hasn't had any activity for a while. It will be closed if no further activity occurs. If you think your issue is still relevant, feel free to comment on it to keep it open. (Read more at #912) Thanks! |
keep alive |
Thanks for bumping! Actually yes this is possible, but I don't think was ever documented.
Providers.Email({
generateVerificationToken: () => { return "ABC123" },
sendVerificationRequest: ({ identifier: email, url, token, site, provider }) => { /* your function */ }
})
For more information on customising the email provider, please see: Additionally, there is also this guide to using SMS for sign in with Everify: This approach uses the credentials callback, which is perfect if you want stateless sign in without a user database - or if you want to use an existing user database in your own way. I want to have built-in support for sending email codes like this, and potentially even make that the default behaviour for the email provider, as it makes it much easier to support cross-device sign in (e.g. start sign in on desktop, get email on phone, enter code on email and you are done). I would also still support signing in by just clicking the button in the email; the messaging would just need to be right to not confuse users (as once the button was clicked the token would "used up" so you wouldn't want them clicking it on their phone by mistake). We would need the built-in The final consideration is that shorter tokens really ought to have a shorter expiry time. This functionality is currently baked in to each database adapter (in the Ideally I would like to see this abstracted out so that it is possible to use the Email provider without a database adapter, if you have these methods defined on the provider, although this is already possible with the existing callbacks (which can be very powerful) as shown in the example blog post. |
For your interest, when #1378 is merged, |
So #1378 is merged and I think Iain gave a good explanation. Can this be closed @alex-cory? |
As said by @iaincollins I need to customize the verify-request page to let the user insert the pin. Once there, what shouold I do with the PIN? My idea is that I have to send it to |
@ramiel were you able to solve this? |
Yes, I was. The only way is to use the version of Regardless of what is written in this issue, next-auth is not ready to have a login with pin just by customising the |
Just jumping in to say I'd also really appreciate this ability! Currently I'm using sessions + magic links for authentication in my habit tracking project and I'm running into the same problem with magic links. Here's an example mobile login flow where magic links on iOS are not working as well as I'd hope
Just reiterating two possible solutions from above, either of which would be fine with me
Thank you for all of the work on this great library, the NextJS development experience has been a breath of fresh air thanks to all the cool libraries like this one :) |
OTP is already possible. We implemented it with next-auth at Hypersay Events . |
@ramiel I agree it looks possible but I wish it had first party support though the Email provider using a configuration option like If you have some time on your hands I'd really appreciate a write up of the steps needed to use OTP for email auth! I see you have a blog, I think this would make an awesome post if you happen to have the time / desire to do one :) |
@trentprynn your wish is an order :D |
@ramiel so awesome! thank you so much, I really appreciate it :) |
For a prototype, I guess that would be alright |
This is awesome! For whatever reason tho I can't seem to get it to work on mobile. Have you noticed this as well? |
For anyone interested, I created a much-simplified version, based on @ramiel's blog post: |
Here's a strategy/hack to support magic code without a database adapter and without implementing custom UI. Demo: Screencast.from.2023-01-09.21-31-58.webmI might do a proper writeup later but the idea is:
Code: import cookie from "cookie";
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { NextApiHandler } from "next";
const handler: NextApiHandler = async (req, res) => {
if (
req.query.nextauth !== undefined &&
req.query.nextauth[0] === "callback" &&
req.query.nextauth[1] === "otp-generation" &&
req.method === "POST"
) {
const { email } = req.body;
if (!IMPLEMENTME_isValidEmail(email)) {
return res.status(400).end();
}
const code = await IMPLEMENTME_generateOtp();
await IMPLEMENTME_saveOtpForUser(email, code);
await IMPLEMENTME_sendOtpToUser(email, code);
res.setHeader(
"set-cookie",
cookie.serialize("otp-flow.user-email", req.body.email, {
httpOnly: true,
maxAge: 5 * 60, // 5 minutes
path: "/",
})
);
return res.redirect("/api/auth/signin");
}
const isOtpFlowInProgress = req.cookies["otp-flow.user-email"] !== undefined;
return NextAuth({
providers: isOtpFlowInProgress
? [
CredentialsProvider({
id: "otp-verification",
name: "Magic Code",
credentials: {
code: {
label: "Code",
type: "text",
placeholder: "Enter the code you received via email",
},
},
async authorize(credentials, _req) {
const email = req.cookies["otp-flow.user-email"];
const code = credentials?.code;
if (email === undefined || code === undefined) {
return null;
}
if (!(await IMPLEMENTME_isOtpValid(email, code))) {
return null;
}
const user = await IMPLEMENTME_findOrCreateUser(email);
res.setHeader(
"set-cookie",
cookie.serialize("otp-flow.user-email", "", {
maxAge: -1,
path: "/",
})
);
return user;
},
}),
]
: [
CredentialsProvider({
id: "otp-generation",
name: "Magic Code",
credentials: {
email: {
label: "Email",
type: "email",
placeholder: "Your email address",
},
},
async authorize() {
return null;
},
}),
],
})(req, res);
};
export default handler; |
Is this possible with AuthJs and svelteKit? I already made solution with email provider, but as my sveltekit will be used with pwa, I saw on ios I cannot redirect magic link to installed app on homescreen only safari browser, so I quess this solution with otp can be helpful. Any code solution for svelteKit and authJS with magic code? |
@nmicun if you're referring to the strategy I posted above, it uses server-rendered pages ony, so I'd imagine it would work regardless of the framework you're using for your front end. |
hello @bard thanks for your reply. I'm on very beginning with SvelteKit and all of this, that's why I asked if someone has already example there. For Email provider with magic link, its very easy to setup as its built in, but for this I'm not sure where to add changes. I also follow @balazsorban44 solution, but I think its not the same with @auth/sveltekit. |
Sorry @nmicun, my brain is still stuck at when AuthJS was only Indeed, I see that sveltekit comes with a different backend altogether, so the above might not be applicable. Hopefully someone familiar with it can chime in. |
looks like @balazsorban44 solution is compatible with sveltekit too. not sure for now how to keep user on same page after click signIn button, or maybe how to redirect on new page with only code input field but to pass email info also. |
Do you have a working code example of this somewhere on the site? The page details seem to be missing some pieces or an older version from V4 changes maybe. An example repo would be very helpful on this. |
Hi! Are there any updates on this regarding a built-in option? |
Would love to have this built-in as well. I am running auth/core in production and using email sign up. Users often land on the auth-error page because:
I talked about it here: #7524 but no reaction yet :) |
Had this same issue, tried the HEAD early return method and a few other things. Turns out for me it was pretty straightforward - mobile devices tend to auto capitalize the first letter, the callback url appears to be case sensitive. I ended up using the following for the callback (call window.location.href = "/api/auth/callback/email?email=" + encodeURIComponent(inputEmail.toLowerCase().trim()) + "&token=" + encodeURIComponent(code.trim()); |
Has anyone got |
probably hashed value |
@jmcelreavey I do this: generateVerificationToken: () => {
const random = crypto.getRandomValues(new Uint8Array(8));
return Buffer.from(random).toString('hex').slice(0, 6);
}, It generates a random string of 6 characters [a-z,0-9] Full emailprovider object looks like this (this is in SvelteKit +hooks.server.ts): EmailProvider({
server: EMAIL_SERVER,
from: EMAIL_FROM,
maxAge: 15 * 60, // 15 minutes
generateVerificationToken: () => {
const random = crypto.getRandomValues(new Uint8Array(8));
return Buffer.from(random).toString('hex').slice(0, 6);
},
sendVerificationRequest(params) {
customSendVerificationRequest(params);
}
}), |
Would LOVE to see built in OTP for email or customizable for SMS :) |
Up! It's merged not in this repo. |
Anyone using phone numbers instead of emails? (SMS / WhatsApp, etc) What does this identifier look like? |
I know this is really old issue, but anyway. My solution: Server (auth config): providers: [
Nodemailer({
id: "email-code",
server: {
host: env.SMTP_HOST,
port: env.SMTP_PORT,
auth: {
user: env.SMTP_USER,
pass: env.SMTP_PASSWORD,
},
},
from: env.EMAIL_FROM,
generateVerificationToken() {
const code = Math.floor(100000 + Math.random() * 900000); // random 6-digit code
return code.toString();
},
sendVerificationRequest: sendVerificationRequestCode, // Just make it magic-code view, it's easy. sendVerificationRequest well-documented.
}),
// ... Client: const checkToken = async (email: string, token: string) => {
const url = new URL("/api/auth/callback/email-code", window.location.href);
url.searchParams.append("email", email);
url.searchParams.append("token", token);
const response = await fetch(url.href);
const responseUrl = new URL(response.url, window.location.href); // Final url with all redirects
const errorSearchParam = responseUrl.searchParams.get("error");
if (errorSearchParam === null) { // Everything fine.
return true;
}
throw new Error(
`Error during token check: ${errorSearchParam}. URL: ${response.url}`,
);
}; After successful |
Hi, This code does works well, but I feel that there is not much reason to heavily rely on auth.js if you use |
Your question
I'm curious if there's currently a way to have the same behavior as the magic link, but instead send a 4-6 digit code to their email that the user can then enter in themselves on the site.
Also kind of like this but with email code instead of SMS code.
What are you trying to do
I'm working on a PWA and a magic link will take you directly to the mobile browser (ex: iOS Safari) instead of directly to the PWA. This is a way to get around that.
Feedback
The text was updated successfully, but these errors were encountered: