Skip to main content
GET
/
audit
Get Audit Logs
curl --request GET \
  --url https://auth.nullpass.xyz/api/audit \
  --header 'Authorization: Bearer <token>'
{
  "logs": [
    {
      "id": "<string>",
      "action": "<string>",
      "data": {},
      "createdAt": "2023-11-07T05:31:56Z"
    }
  ],
  "total": 123,
  "limit": 123,
  "offset": 123
}

Endpoint

GET /api/audit

Overview

Retrieves audit logs for the authenticated user. IP addresses in log data are automatically decrypted for display.
IP Address Encryption: IP addresses stored in audit logs are encrypted using AES-256-GCM with user-specific keys. They are automatically decrypted when retrieved via this API endpoint. See IP Encryption for implementation details.

Request

Requires authentication via Bearer token.

Query Parameters

limit
number
default:"50"
Maximum number of logs to return (max 100)
offset
number
default:"0"
Number of logs to skip (for pagination)
action
string
Filter by audit action type (e.g., “USER_LOGIN”, “PASSWORD_CHANGE”)

Response

logs
array
Array of audit log entries
total
number
Total number of logs matching the filter
limit
number
Limit used in the query
offset
number
Offset used in the query

Implementation Details

Code Reference

export async function GET(request: NextRequest) {
  const corsResponse = handleCors(request)
  if (corsResponse) return corsResponse

  const blocked = await protectRoute(request)
  if (blocked) return blocked

  const auth = await requireAuth(request)
  if ('error' in auth) return auth.error

  try {
    const { searchParams } = new URL(request.url)
    const limit = parseInt(searchParams.get('limit') || '50')
    const offset = parseInt(searchParams.get('offset') || '0')
    const action = searchParams.get('action')

    const where: any = {
      userId: auth.userId,
    }

    if (action) {
      where.action = action
    }

    const [logs, total] = await Promise.all([
      prisma.auditLog.findMany({
        where,
        orderBy: {
          createdAt: 'desc',
        },
        take: Math.min(limit, 100),
        skip: offset,
        select: {
          id: true,
          action: true,
          data: true,
          createdAt: true,
        },
      }),
      prisma.auditLog.count({ where }),
    ])

    const logsWithDecryptedIp = logs.map(log => {
      const data = log.data as any
      if (data && typeof data === 'object' && 'ip' in data && typeof data.ip === 'string') {
        return {
          ...log,
          data: {
            ...data,
            ip: decryptIp(data.ip, auth.userId),
          },
        }
      }
      return log
    })

    return jsonResponse(
      {
        logs: logsWithDecryptedIp,
        total,
        limit,
        offset,
      },
      200,
      request.headers.get('origin')
    )
  } catch (error) {
    console.error('Get audit logs error:', error)
    return errorResponse('Internal server error', 500, request.headers.get('origin'))
  }
}

Status Codes

200
OK
Success
401
Unauthorized
Missing or invalid authentication token

Example Requests

Get All Logs

curl -X GET https://auth.nullpass.xyz/api/audit \
  -H "Authorization: Bearer YOUR_TOKEN"

Get Logs with Pagination

curl -X GET "https://auth.nullpass.xyz/api/audit?limit=20&offset=0" \
  -H "Authorization: Bearer YOUR_TOKEN"

Filter by Action

curl -X GET "https://auth.nullpass.xyz/api/audit?action=USER_LOGIN" \
  -H "Authorization: Bearer YOUR_TOKEN"

Example Response

{
  "logs": [
    {
      "id": "clx1234567890",
      "action": "USER_LOGIN",
      "data": {
        "ip": "192.168.1.1",
        "twoFactorUsed": false
      },
      "createdAt": "2024-01-01T00:00:00.000Z"
    },
    {
      "id": "clx0987654321",
      "action": "PASSWORD_CHANGE",
      "data": {},
      "createdAt": "2024-01-02T00:00:00.000Z"
    }
  ],
  "total": 2,
  "limit": 50,
  "offset": 0
}

Security Notes

  • Users can only view their own audit logs
  • IP addresses are automatically decrypted from storage format
  • Maximum limit is 100 logs per request
  • Logs are ordered by creation date (newest first)

Authorizations

Authorization
string
header
required

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

Query Parameters

limit
integer
default:50

Maximum number of logs to return (max 100)

Required range: x <= 100
offset
integer
default:0

Number of logs to skip (for pagination)

action
string

Filter by audit action type (e.g., "USER_LOGIN", "PASSWORD_CHANGE")

Response

Audit logs

logs
object[]
total
integer
limit
integer
offset
integer