Dorji Tshering
Dorji Tshering
CCConvex Community
Created by Dorji Tshering on 8/15/2024 in #support-community
Password reset not working.
@Michal Srb Tried right now again and it's working as expected. May be it just needed a server restart or something. Anyway thanks for your time!! Appreciated.
14 replies
CCConvex Community
Created by Dorji Tshering on 8/15/2024 in #support-community
Password reset not working.
Hi @Michal Srb, here is the link to minimal reproduction of the issue. https://github.com/dorji-dev/convex-auth. Funnily enough, if i manually pass the email that has account, like this in the resend config, it works.
export const ResendOTPPasswordReset = Resend({
id: "resend-otp",
apiKey: process.env.AUTH_RESEND_KEY,
async generateVerificationToken() {
return generateRandomString(8, alphabet("0-9"));
},
async sendVerificationRequest({ identifier: email, provider, token }) {
const resend = new ResendAPI(provider.apiKey);
const { error } = await resend.emails.send({
from: "Lhakhang Service <kk@resend.dev>",
to: ["dorji.codes@gmail.com"],
subject: `Reset your password in Lhakhang Service`,
text: "Your password reset code is " + token,
});

if (error) {
throw new Error("Could not send");
}
},
});
export const ResendOTPPasswordReset = Resend({
id: "resend-otp",
apiKey: process.env.AUTH_RESEND_KEY,
async generateVerificationToken() {
return generateRandomString(8, alphabet("0-9"));
},
async sendVerificationRequest({ identifier: email, provider, token }) {
const resend = new ResendAPI(provider.apiKey);
const { error } = await resend.emails.send({
from: "Lhakhang Service <kk@resend.dev>",
to: ["dorji.codes@gmail.com"],
subject: `Reset your password in Lhakhang Service`,
text: "Your password reset code is " + token,
});

if (error) {
throw new Error("Could not send");
}
},
});
. I can confirm that the incoming email is coming as string after logging. Let me know if you have any other related questions.
14 replies
CCConvex Community
Created by Dorji Tshering on 8/15/2024 in #support-community
Password reset not working.
@Michal Srb Sure will do that and let you know.
14 replies
CCConvex Community
Created by Dorji Tshering on 8/15/2024 in #support-community
Password reset not working.
Yup the value is coming correct. Could you give me a link to that demo, so i can try it locally? I think that will help in narrow down the issue.
14 replies
CCConvex Community
Created by Dorji Tshering on 8/15/2024 in #support-community
Password reset not working.
@Michal Srb Yes Michal, I can see the document there with povider as password and the email as the value for providerAccountId field
14 replies
CCConvex Community
Created by Dorji Tshering on 8/15/2024 in #support-community
Password reset not working.
And finally my client form handler:
const sendResetPasswordEmail = async (
formValues: z.infer<typeof forgotPasswordSchema>,
) => {
await signIn("password", {
flow: "reset",
email: formValues.email,
})
.then(() =>
toast({
title: "Success",
description: `An email has been sent to ${formValues.email} with a password reset link`,
}),
)
.catch(() =>
toast({
title: "Failure",
variant: "destructive",
description:
"Failed to send password reset link. Make sure account is associated with the given email",
}),
);
};
const sendResetPasswordEmail = async (
formValues: z.infer<typeof forgotPasswordSchema>,
) => {
await signIn("password", {
flow: "reset",
email: formValues.email,
})
.then(() =>
toast({
title: "Success",
description: `An email has been sent to ${formValues.email} with a password reset link`,
}),
)
.catch(() =>
toast({
title: "Failure",
variant: "destructive",
description:
"Failed to send password reset link. Make sure account is associated with the given email",
}),
);
};
. Initially there was an error from resend that the test emails must be the email associated with the resend account. Tried that email but got the error Uncaught Error: InvalidAccountId at retrieveAccount. Then i created an account with that email and i can see that user both on users table and it's id associated with an account under authAccounts table. Now when i try again with that email, I am getting the error Uncaught Error: InvalidAccountId at retrieveAccount. What could be the reason?
14 replies
CCConvex Community
Created by Dorji Tshering on 8/15/2024 in #support-community
Password reset not working.
Below is my auth.ts file.
import { Password } from "@convex-dev/auth/providers/Password";
import { convexAuth } from "@convex-dev/auth/server";
import { GenericMutationCtx } from "convex/server";

import { DataModel } from "./_generated/dataModel";
import { ResendOTPPasswordReset } from "./services/passwordReset";

export const { auth, signIn, signOut, store } = convexAuth({
providers: [Password({ reset: ResendOTPPasswordReset })],
callbacks: {
async createOrUpdateUser(ctx: GenericMutationCtx<DataModel>, args) {
if (args.existingUserId) {
return args.existingUserId;
}
const existingUser = await ctx.db
.query("users")
.withIndex("email", (q) => q.eq("email", args.profile.email))
.first();

if (existingUser) {
return existingUser._id;
}
return ctx.db.insert("users", {
email: args.profile.email,
});
},
},
});
import { Password } from "@convex-dev/auth/providers/Password";
import { convexAuth } from "@convex-dev/auth/server";
import { GenericMutationCtx } from "convex/server";

import { DataModel } from "./_generated/dataModel";
import { ResendOTPPasswordReset } from "./services/passwordReset";

export const { auth, signIn, signOut, store } = convexAuth({
providers: [Password({ reset: ResendOTPPasswordReset })],
callbacks: {
async createOrUpdateUser(ctx: GenericMutationCtx<DataModel>, args) {
if (args.existingUserId) {
return args.existingUserId;
}
const existingUser = await ctx.db
.query("users")
.withIndex("email", (q) => q.eq("email", args.profile.email))
.first();

if (existingUser) {
return existingUser._id;
}
return ctx.db.insert("users", {
email: args.profile.email,
});
},
},
});
14 replies
CCConvex Community
Created by Dorji Tshering on 8/13/2024 in #support-community
Convex auth `signOut` does not delete auth cookies like authJWT and refresh tokens in production
Superb!! @Michal Srb
12 replies
CCConvex Community
Created by Delveroff on 8/4/2024 in #support-community
ConvexAuth+Next.js: should I implement `/api/sign-in`?
@Michal Srb I was searching through the convex docs instead auth docs my bad. Thank you so much for your help. Feels really confident going forward with convex. Really appreciate for your time!!!
55 replies
CCConvex Community
Created by Delveroff on 8/4/2024 in #support-community
ConvexAuth+Next.js: should I implement `/api/sign-in`?
@Michal Srb This is the error I am getting: Uncaught Error: Missing JWT_PRIVATE_KEY environment variable. For development, I see those env but for production I don't see those, I don't exactly know how dev envs were generated. Should I be using same key for both? Plus I also see other two envs under dev deployment i.e. JWKS and SITE_URL. Do i need to define those in prod deployment as well?
55 replies
CCConvex Community
Created by Delveroff on 8/4/2024 in #support-community
ConvexAuth+Next.js: should I implement `/api/sign-in`?
By the way everything is working locally, signin, signup, signout.
55 replies
CCConvex Community
Created by Delveroff on 8/4/2024 in #support-community
ConvexAuth+Next.js: should I implement `/api/sign-in`?
import {
convexAuthNextjsMiddleware,
createRouteMatcher,
isAuthenticatedNextjs,
nextjsMiddlewareRedirect,
} from "@convex-dev/auth/nextjs/server";
import { NextResponse } from "next/server";
import createIntlMiddleware from "next-intl/middleware";

import { LOCALES } from "./i18n/locales";

export default convexAuthNextjsMiddleware((request) => {
const isApiRoute = createRouteMatcher(["/api(.*)"]);

if (isApiRoute(request)) {
return NextResponse.next();
} else {
const handleI18nRouting = createIntlMiddleware({
locales: LOCALES,
defaultLocale: "en",
});

const response = handleI18nRouting(request);

const locale = new URL(
response.headers.get("location") || request.url,
).pathname.split("/")[1];

const isAuthPage = createRouteMatcher([`/${locale}/auth(.*)`]);
const isProtectedRoute = createRouteMatcher([`/${locale}/dashboard(.*)`]);

if (isAuthPage(request) && isAuthenticatedNextjs()) {
return nextjsMiddlewareRedirect(request, `/${locale}`);
}
if (isProtectedRoute(request) && !isAuthenticatedNextjs()) {
return nextjsMiddlewareRedirect(request, `/${locale}`);
}
return response;
}
});

export const config = {
/*
* Match all request paths except for the ones starting with:
* - _next/static (static files)
* - _next/image (image optimization files)
* - images (assets inside images folder under public)
* - favicon.ico (favicon file)
*/
matcher: ["/((?!_next/static|_next/image|images|assets|favicon.ico).*)"],
};
import {
convexAuthNextjsMiddleware,
createRouteMatcher,
isAuthenticatedNextjs,
nextjsMiddlewareRedirect,
} from "@convex-dev/auth/nextjs/server";
import { NextResponse } from "next/server";
import createIntlMiddleware from "next-intl/middleware";

import { LOCALES } from "./i18n/locales";

export default convexAuthNextjsMiddleware((request) => {
const isApiRoute = createRouteMatcher(["/api(.*)"]);

if (isApiRoute(request)) {
return NextResponse.next();
} else {
const handleI18nRouting = createIntlMiddleware({
locales: LOCALES,
defaultLocale: "en",
});

const response = handleI18nRouting(request);

const locale = new URL(
response.headers.get("location") || request.url,
).pathname.split("/")[1];

const isAuthPage = createRouteMatcher([`/${locale}/auth(.*)`]);
const isProtectedRoute = createRouteMatcher([`/${locale}/dashboard(.*)`]);

if (isAuthPage(request) && isAuthenticatedNextjs()) {
return nextjsMiddlewareRedirect(request, `/${locale}`);
}
if (isProtectedRoute(request) && !isAuthenticatedNextjs()) {
return nextjsMiddlewareRedirect(request, `/${locale}`);
}
return response;
}
});

export const config = {
/*
* Match all request paths except for the ones starting with:
* - _next/static (static files)
* - _next/image (image optimization files)
* - images (assets inside images folder under public)
* - favicon.ico (favicon file)
*/
matcher: ["/((?!_next/static|_next/image|images|assets|favicon.ico).*)"],
};
55 replies
CCConvex Community
Created by Delveroff on 8/4/2024 in #support-community
ConvexAuth+Next.js: should I implement `/api/sign-in`?
@Michal Srb I would like to continue here since it is also related to the OP question. I have deployed my app to vercel and I am getting the error EDGE_FUNCTION_INVOCATION_FAILED. Below is my log:
Error: [Request ID: 2bc8eabac770964d] Server Error
at (node_modules/convex/dist/esm/browser/http_client.js:258:0)
at (node_modules/@convex-dev/auth/dist/nextjs/server/proxy.js:21:0)
at (node_modules/@convex-dev/auth/dist/nextjs/server/index.js:49:0)
at (node_modules/next/dist/esm/server/web/adapter.js:158:0)
Error: [Request ID: 2bc8eabac770964d] Server Error
at (node_modules/convex/dist/esm/browser/http_client.js:258:0)
at (node_modules/@convex-dev/auth/dist/nextjs/server/proxy.js:21:0)
at (node_modules/@convex-dev/auth/dist/nextjs/server/index.js:49:0)
at (node_modules/next/dist/esm/server/web/adapter.js:158:0)
. And the request path for the error is /api/auth. Below is my middleware as it stands if it would help provide more context:
55 replies
CCConvex Community
Created by Delveroff on 8/4/2024 in #support-community
ConvexAuth+Next.js: should I implement `/api/sign-in`?
@Michal Srb Oh wow, how did i miss that! Yup that was the issue, now working thanks a lot!!!!
55 replies
CCConvex Community
Created by Delveroff on 8/4/2024 in #support-community
ConvexAuth+Next.js: should I implement `/api/sign-in`?
import {
convexAuthNextjsMiddleware,
createRouteMatcher,
isAuthenticatedNextjs,
nextjsMiddlewareRedirect,
} from "@convex-dev/auth/nextjs/server";
import createIntlMiddleware from "next-intl/middleware";

import { LOCALES } from "./i18n/locales";

export default convexAuthNextjsMiddleware((request) => {
// Create and call the next-intl middleware
const handleI18nRouting = createIntlMiddleware({
// A list of all locales that are supported
locales: LOCALES,
// Used when no locale matches
defaultLocale: "en",
});

const response = handleI18nRouting(request);

const locale = new URL(
response.headers.get("location") || request.url,
).pathname.split("/")[1];

const isAuthPage = createRouteMatcher([`/${locale}/auth(.*)`]);
const isProtectedRoute = createRouteMatcher([`/${locale}/dashboard(.*)`]);

if (isAuthPage(request) && isAuthenticatedNextjs()) {
return nextjsMiddlewareRedirect(request, `/${locale}`);
}
if (isProtectedRoute(request) && !isAuthenticatedNextjs()) {
return nextjsMiddlewareRedirect(request, `/${locale}/auth/login`);
}
return response;
});

export const config = {
/*
* Match all request paths except for the ones starting with:
* - api (API routes)
* - _next/static (static files)
* - _next/image (image optimization files)
* - images (assets inside images folder under public)
* - favicon.ico (favicon file)
*/
matcher: ["/((?!api|_next/static|_next/image|images|assets|favicon.ico).*)"],
};
import {
convexAuthNextjsMiddleware,
createRouteMatcher,
isAuthenticatedNextjs,
nextjsMiddlewareRedirect,
} from "@convex-dev/auth/nextjs/server";
import createIntlMiddleware from "next-intl/middleware";

import { LOCALES } from "./i18n/locales";

export default convexAuthNextjsMiddleware((request) => {
// Create and call the next-intl middleware
const handleI18nRouting = createIntlMiddleware({
// A list of all locales that are supported
locales: LOCALES,
// Used when no locale matches
defaultLocale: "en",
});

const response = handleI18nRouting(request);

const locale = new URL(
response.headers.get("location") || request.url,
).pathname.split("/")[1];

const isAuthPage = createRouteMatcher([`/${locale}/auth(.*)`]);
const isProtectedRoute = createRouteMatcher([`/${locale}/dashboard(.*)`]);

if (isAuthPage(request) && isAuthenticatedNextjs()) {
return nextjsMiddlewareRedirect(request, `/${locale}`);
}
if (isProtectedRoute(request) && !isAuthenticatedNextjs()) {
return nextjsMiddlewareRedirect(request, `/${locale}/auth/login`);
}
return response;
});

export const config = {
/*
* Match all request paths except for the ones starting with:
* - api (API routes)
* - _next/static (static files)
* - _next/image (image optimization files)
* - images (assets inside images folder under public)
* - favicon.ico (favicon file)
*/
matcher: ["/((?!api|_next/static|_next/image|images|assets|favicon.ico).*)"],
};
55 replies
CCConvex Community
Created by Delveroff on 8/4/2024 in #support-community
ConvexAuth+Next.js: should I implement `/api/sign-in`?
@Michal Srb I am also facing a similar issue so thought to continue here. I have followed the documentation without missing anything for the email & password signin. However my set up is quite different as in, I have i18n set up, and also I am combining the convex middleware with i18n middleware. On signin, the request is being sent to /api/auth which returns 404. However, if i remove i18n setup and default exporting the convex middleware, it works(with an exception that I also have to pass flow property to the signIn function from convex to be either signIn or signUp which doesn't seem to be documented yet.). I believe the issue lies in the middleware composition. Would really appreciate if there is a documentation on how to combine convex middleware with others. My middleware file currently:
55 replies