Authentication
List Active Sessions
Get the list of active sessions for the current authenticated user, with device + masked IP + isCurrent flag.
GET /api/v1/auth/sessions — 🔑 User-auth (Bearer JWT) · Rate limit: 30 req / hour
Returns the current user's active session list. Each entry includes the device (parsed User-Agent), masked IP, last-active timestamp, and an isCurrent flag indicating which session matches the requesting refresh token.
Use this endpoint to power "Active sessions" UI in account settings. Combine with DELETE /auth/sessions/{id} (revoke one) and POST /auth/sessions/revoke-all (revoke all except current).
Request
Headers
| Header | Value | Notes |
|---|---|---|
Authorization | Bearer <accessToken> | Required |
Cookie: biore_refresh=... | (auto) | Used to determine isCurrent flag |
No body, no query params.
Response
200 OK — ApiResponseOf<SessionListResponseDto>
{
"success": true,
"data": {
"sessions": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"device": "Chrome on macOS",
"ipMasked": "192.168.1.***",
"location": null,
"isCurrent": true,
"createdAt": "2026-04-20T10:30:00.000Z",
"lastActiveAt": "2026-04-29T18:45:23.000Z"
},
{
"id": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
"device": "Safari on iOS",
"ipMasked": "10.0.0.***",
"location": null,
"isCurrent": false,
"createdAt": "2026-04-15T08:00:00.000Z",
"lastActiveAt": "2026-04-28T12:15:00.000Z"
}
]
}
}SessionItemDto fields
| Field | Type | Notes |
|---|---|---|
id | string (UUID) | Session ID — pass to DELETE /auth/sessions/{id} to revoke |
device | string | null | Parsed from Session.userAgent (e.g., "Chrome on macOS") |
ipMasked | string | null | IP with last octet masked (192.168.1.***) |
location | string | null | Reserved for future GeoIP integration (currently null) |
isCurrent | boolean | true for the session that matches the requesting refresh token |
createdAt | string (ISO 8601) | When the session was created (login time) |
lastActiveAt | string (ISO 8601) | Last refresh or API call timestamp |
Errors
| HTTP | code / i18nKey | Reason |
|---|---|---|
401 | (no JWT or invalid) | Not authenticated |
429 | (throttle) | Rate limit exceeded (30 req/hour) |
Side effects
- Read all
Sessionrows foruserIdwhererevokedAt = nullandexpiresAt > now(). - Hash the requesting refresh token from cookie → match against
Session.refreshTokenHashto determineisCurrent. - Mask IPs (last octet) before serialization.
- No mutations.
Code samples
curl -X GET https://api.bio.re/api/v1/auth/sessions \
-H 'Authorization: Bearer <accessToken>' \
-b cookies.txttype Session = {
id: string;
device: string | null;
ipMasked: string | null;
location: string | null;
isCurrent: boolean;
createdAt: string;
lastActiveAt: string;
};
async function getSessions(accessToken: string): Promise<{ sessions: Session[] }> {
const res = await fetch('https://api.bio.re/api/v1/auth/sessions', {
headers: { 'Authorization': `Bearer ${accessToken}` },
credentials: 'include',
});
const json = await res.json();
if (!res.ok || !json.success) {
throw Object.assign(new Error(json?.error?.message ?? 'Failed'), {
code: json?.error?.code,
});
}
return json.data;
}import { useQuery } from '@tanstack/react-query';
export const sessionKeys = {
all: ['auth', 'sessions'] as const,
};
export function useSessions() {
return useQuery({
queryKey: sessionKeys.all,
queryFn: async () => {
const res = await fetch('/api/v1/auth/sessions', {
credentials: 'include',
headers: { 'Authorization': `Bearer ${getAccessToken()}` },
});
const json = await res.json();
if (!res.ok || !json.success) {
throw Object.assign(new Error(json?.error?.message ?? 'Failed'), {
code: json?.error?.code,
});
}
return json.data as { sessions: Session[] };
},
});
}Try it
Authorization
bearer AuthorizationBearer <token>
In: header
Response Body
application/json
application/json
curl -X GET "https://loading/api/v1/auth/sessions"{
"success": true,
"data": {
"sessions": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"device": "Chrome on macOS",
"ipMasked": "192.168.1.***",
"location": null,
"isCurrent": false,
"createdAt": "2026-04-20T10:30:00.000Z",
"lastActiveAt": "2026-04-20T10:30:00.000Z"
}
]
}
}{
"success": false,
"error": {
"code": "AUTH_UNAUTHORIZED",
"message": "Invalid credentials",
"i18nKey": "auth.login.invalid_credentials",
"i18nVars": {
"field": "email"
},
"details": [
{
"message": "email must be an email"
}
],
"correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}Source
| Source | Path | Lines |
|---|---|---|
| Controller | apps/api-core/src/modules/auth/auth.controller.ts | 244–278 (getSessions) |
| DTO (response) | apps/api-core/src/modules/auth/dto/response.dto.ts | 85–106 (SessionItemDto), 108–111 (SessionListResponseDto) |
| Service | apps/api-core/src/modules/auth/auth.service.ts | getSessions() |
| Prisma model | packages/prisma/prisma/schema.prisma | Session |