Skip to content

Commit be0c7db

Browse files
committed
feat: access tokens when you verify
1 parent 82d1b65 commit be0c7db

1 file changed

Lines changed: 64 additions & 3 deletions

File tree

src/controllers/magicLinks.ts

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,24 @@ import { Request, Response } from 'express';
77
import { Op } from 'sequelize';
88

99
import { getSystemConfig } from '../config/getSystemConfig';
10+
import { setAuthCookies } from '../lib/cookie';
11+
import { generateRefreshToken, hashRefreshToken, signAccessToken } from '../lib/token';
12+
import { AuthEvent } from '../models/authEvents';
1013
import { MagicLinkToken } from '../models/magicLinks';
14+
import { Session } from '../models/sessions';
1115
import { User } from '../models/users';
12-
import { MagicLinkVerifyQuerySchema } from '../schemas/magicLink.schema';
1316
import { AuthEventService } from '../services/authEventService';
1417
import { sendMagicLinkEmail } from '../services/messagingService';
1518
import { AuthenticatedRequest } from '../types/types';
16-
import { hashDeviceFingerprint, hashSha256 } from '../utils/utils';
19+
import {
20+
computeSessionTimes,
21+
hashDeviceFingerprint,
22+
hashSha256,
23+
parseDurationToSeconds,
24+
} from '../utils/utils';
1725

1826
const TTL_MINUTES = 15;
27+
const AUTH_MODE: 'web' | 'server' = process.env.AUTH_MODE! as 'web' | 'server';
1928

2029
export async function requestMagicLink(req: Request, res: Response) {
2130
const authReq = req as AuthenticatedRequest;
@@ -166,7 +175,59 @@ export async function pollMagicLinkConfirmation(req: Request, res: Response) {
166175
type: 'magic_link_poll_completed_successfully',
167176
req,
168177
});
169-
return res.status(200).json({ message: 'Success' });
178+
179+
const refreshToken = generateRefreshToken();
180+
const refreshTokenHash = await hashRefreshToken(refreshToken);
181+
const { expiresAt, idleExpiresAt } = computeSessionTimes();
182+
183+
const session = await Session.create({
184+
userId: user.id,
185+
infraId: process.env.APP_ID!,
186+
mode: AUTH_MODE,
187+
refreshTokenHash,
188+
userAgent: req.get('user-agent'),
189+
ipAddress: req.ip,
190+
expiresAt,
191+
idleExpiresAt,
192+
lastUsedAt: undefined,
193+
});
194+
195+
const token = await signAccessToken(session.id, user.id, user.roles);
196+
197+
user.challenge = '';
198+
user.verified = true;
199+
200+
await user.save();
201+
202+
if (token && refreshToken) {
203+
await AuthEvent.create({
204+
user_id: user.id,
205+
type: 'registration_success',
206+
ip_address: req.ip,
207+
user_agent: req.headers['user-agent'],
208+
metadata: {},
209+
});
210+
211+
if (AUTH_MODE === 'web') {
212+
await setAuthCookies(res, { accessToken: token, refreshToken });
213+
res.status(200).json({ message: 'Success' });
214+
return;
215+
}
216+
217+
const { access_token_ttl, refresh_token_ttl } = await getSystemConfig();
218+
219+
return res.status(200).json({
220+
message: 'Success',
221+
token,
222+
refreshToken,
223+
sub: user.id,
224+
roles: user.roles,
225+
email: user.email,
226+
phone: user.phone,
227+
ttl: parseDurationToSeconds(access_token_ttl || '15m'),
228+
refreshTtl: parseDurationToSeconds(refresh_token_ttl || '1h'),
229+
});
230+
}
170231
}
171232

172233
return res.status(204).json({ error: 'Not verified.' });

0 commit comments

Comments
 (0)