You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

126 lines
3.3 KiB

// server/api/auth/login.post.ts
/**
* POST /api/auth/login
*
* Direct login with email and password (no OAuth2 redirect)
*
* Request body:
* {
* "email": "user@example.com",
* "password": "SecureP@ssw0rd"
* }
*
* Response:
* {
* "success": true
* }
*
* Creates session cookie on success
*/
import { z } from 'zod'
import { eq } from 'drizzle-orm'
import { users } from '../../database/schema'
const loginSchema = z.object({
email: z.string().email('Invalid email address'),
password: z.string().min(1, 'Password is required'),
})
export default defineEventHandler(async (event) => {
// 1. Validate request body
const body = await readBody(event)
const { email, password } = loginSchema.parse(body)
try {
// 2. Authenticate with Cidaas (Resource Owner Password Credentials flow)
const tokens = await loginWithPassword(email, password)
// 3. Validate ID token (JWT)
const idTokenPayload = await verifyIdToken(tokens.id_token)
// 4. Fetch user info from Cidaas
const cidaasUser = await fetchUserInfo(tokens.access_token)
// 5. Create/update user in local database
const db = useDatabase()
let user = await db.query.users.findFirst({
where: eq(users.experimentaId, cidaasUser.sub),
})
if (!user) {
// First time login - create user profile
const [newUser] = await db
.insert(users)
.values({
experimentaId: cidaasUser.sub,
email: cidaasUser.email,
firstName: cidaasUser.given_name || '',
lastName: cidaasUser.family_name || '',
})
.returning()
user = newUser
// Auto-assign 'private' role on first login
await assignRoleToUser(newUser.id, 'private', {
adminNotes: 'Auto-assigned on first login',
})
} else {
// Update last login timestamp
await db
.update(users)
.set({
updatedAt: new Date(),
})
.where(eq(users.id, user.id))
// Safety check: If existing user has no roles, assign 'private' role
const userRoleCodes = await getUserApprovedRoleCodes(user.id)
if (userRoleCodes.length === 0) {
await assignRoleToUser(user.id, 'private', {
adminNotes: 'Auto-assigned for existing user without roles',
})
}
}
// 6. Create encrypted session
await setUserSession(event, {
user: {
id: user.id,
experimentaId: user.experimentaId,
email: user.email,
firstName: user.firstName,
lastName: user.lastName,
},
accessToken: tokens.access_token, // Store for logout
loggedInAt: new Date().toISOString(),
})
// 7. Return success
return {
success: true,
}
} catch (error: any) {
console.error('Login error:', error)
// Handle specific error cases
if (error.statusCode === 401) {
// Set response status and return error as JSON body
// This ensures umlauts are properly encoded in the response body
setResponseStatus(event, 401, 'Invalid credentials')
return {
success: false,
message: 'Ungültige E-Mail-Adresse oder Passwort',
}
}
setResponseStatus(event, 500, 'Login failed')
return {
success: false,
message: 'Anmeldung fehlgeschlagen',
}
}
})