BIO.RE
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

HeaderValueNotes
AuthorizationBearer <accessToken>Required
Cookie: biore_refresh=...(auto)Used to determine isCurrent flag

No body, no query params.

Response

200 OKApiResponseOf<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

FieldTypeNotes
idstring (UUID)Session ID — pass to DELETE /auth/sessions/{id} to revoke
devicestring | nullParsed from Session.userAgent (e.g., "Chrome on macOS")
ipMaskedstring | nullIP with last octet masked (192.168.1.***)
locationstring | nullReserved for future GeoIP integration (currently null)
isCurrentbooleantrue for the session that matches the requesting refresh token
createdAtstring (ISO 8601)When the session was created (login time)
lastActiveAtstring (ISO 8601)Last refresh or API call timestamp

Errors

HTTPcode / i18nKeyReason
401(no JWT or invalid)Not authenticated
429(throttle)Rate limit exceeded (30 req/hour)

Side effects

  1. Read all Session rows for userId where revokedAt = null and expiresAt > now().
  2. Hash the requesting refresh token from cookie → match against Session.refreshTokenHash to determine isCurrent.
  3. Mask IPs (last octet) before serialization.
  4. No mutations.

Code samples

curl -X GET https://api.bio.re/api/v1/auth/sessions \
  -H 'Authorization: Bearer <accessToken>' \
  -b cookies.txt
type 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

GET
/api/v1/auth/sessions
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

SourcePathLines
Controllerapps/api-core/src/modules/auth/auth.controller.ts244–278 (getSessions)
DTO (response)apps/api-core/src/modules/auth/dto/response.dto.ts85–106 (SessionItemDto), 108–111 (SessionListResponseDto)
Serviceapps/api-core/src/modules/auth/auth.service.tsgetSessions()
Prisma modelpackages/prisma/prisma/schema.prismaSession

On this page