Skip to content

Commit d385b9f

Browse files
committed
allow changing the password when using social logins
1 parent 51e6831 commit d385b9f

File tree

5 files changed

+34
-3
lines changed

5 files changed

+34
-3
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- DropIndex
2+
DROP INDEX "User_username_key";

apps/api/prisma/schema.prisma

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ datasource db {
1313

1414
model User {
1515
id String @id @unique
16-
username String @unique
16+
username String
1717
picture String?
1818
email String?
1919
emailVerified Boolean?

apps/api/src/logto/management-api.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ export class ManagementApiClient {
4747
}
4848

4949
public async verifyPassword(userId: string, password: string) {
50+
if (password.length === 0)
51+
throw new LogtoError({ code: 'session.invalid_credentials', message: 'Invalid credentials.' })
52+
5053
const response = await ofetch<LogtoUser>(joinURL(env.LOGTO_URL, 'api', 'users', userId, 'password', 'verify'), {
5154
method: 'POST',
5255
headers: {
@@ -75,4 +78,20 @@ export class ManagementApiClient {
7578
})
7679
return response
7780
}
81+
82+
public async hasPassword(userId: string) {
83+
const response = await ofetch<{ hasPassword: boolean }>(
84+
joinURL(env.LOGTO_URL, 'api', 'users', userId, 'has-password'),
85+
{
86+
method: 'GET',
87+
headers: {
88+
Authorization: `Bearer ${await this.getToken()}`,
89+
},
90+
}
91+
).catch((err) => {
92+
throw new LogtoError(err.data)
93+
})
94+
95+
return response
96+
}
7897
}

apps/api/src/trpc/routes/user/index.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,17 @@ export const userRouter = router({
100100
)
101101
.mutation(async ({ ctx, input }) => {
102102
try {
103-
await ctx.mm.verifyPassword(ctx.user.id, input.currentPassword)
103+
const [hasPassword, verifyPassword] = await Promise.allSettled([
104+
ctx.mm.hasPassword(ctx.user.id),
105+
ctx.mm.verifyPassword(ctx.user.id, input.currentPassword),
106+
])
107+
108+
if (hasPassword.status === 'rejected') {
109+
throw hasPassword.reason
110+
} else if (verifyPassword.status === 'rejected' && hasPassword.value.hasPassword) {
111+
throw verifyPassword.reason
112+
}
113+
104114
await ctx.mm.updatePassword(ctx.user.id, input.newPassword)
105115
} catch (err) {
106116
if (err instanceof LogtoError && err.code === 'session.invalid_credentials') {

apps/web/pages/user/edit-profile/password.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ definePageMeta({
77
layout: 'auth',
88
})
99
10-
const { claims, fetchContext, signIn } = useLogto()
10+
const { claims, signIn } = useLogto()
1111
const { client } = useTRPC()
1212
const { t } = useI18n()
1313
const { notify } = useNotification()

0 commit comments

Comments
 (0)