> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nullpass.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Audit Logs

> Retrieve user audit logs

## Endpoint

```
GET /api/audit
```

## Overview

Retrieves audit logs for the authenticated user. IP addresses in log data are automatically decrypted for display.

<Info>
  **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](/api-reference/lib/ip-encryption) for implementation details.
</Info>

## Request

Requires authentication via Bearer token.

### Query Parameters

<ParamField query="limit" type="number" default="50">
  Maximum number of logs to return (max 100)
</ParamField>

<ParamField query="offset" type="number" default="0">
  Number of logs to skip (for pagination)
</ParamField>

<ParamField query="action" type="string">
  Filter by audit action type (e.g., "USER\_LOGIN", "PASSWORD\_CHANGE")
</ParamField>

## Response

<ResponseField name="logs" type="array">
  Array of audit log entries

  <Expandable title="Audit Log Entry">
    <ResponseField name="id" type="string">
      Log entry ID
    </ResponseField>

    <ResponseField name="action" type="string">
      Audit action type
    </ResponseField>

    <ResponseField name="data" type="object">
      Additional log data (IP addresses are decrypted)
    </ResponseField>

    <ResponseField name="createdAt" type="string">
      Timestamp of the action
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="total" type="number">
  Total number of logs matching the filter
</ResponseField>

<ResponseField name="limit" type="number">
  Limit used in the query
</ResponseField>

<ResponseField name="offset" type="number">
  Offset used in the query
</ResponseField>

## Implementation Details

### Code Reference

```8:78:nullpass_clean/src/app/api/audit/route.ts theme={null}
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

<ResponseField name="200" type="OK">
  Success
</ResponseField>

<ResponseField name="401" type="Unauthorized">
  Missing or invalid authentication token
</ResponseField>

## Example Requests

### Get All Logs

```bash theme={null}
curl -X GET https://auth.nullpass.xyz/api/audit \
  -H "Authorization: Bearer YOUR_TOKEN"
```

### Get Logs with Pagination

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

### Filter by Action

```bash theme={null}
curl -X GET "https://auth.nullpass.xyz/api/audit?action=USER_LOGIN" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

## Example Response

```json theme={null}
{
  "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)


## OpenAPI

````yaml GET /audit
openapi: 3.1.0
info:
  title: Null Pass API
  description: >-
    Internal API documentation for Null Pass authentication and service
    management system
  version: 1.0.0
servers:
  - url: https://auth.nullpass.xyz/api
security: []
paths:
  /audit:
    get:
      summary: Get Audit Logs
      description: Retrieve user audit logs
      parameters:
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            default: 50
            maximum: 100
          description: Maximum number of logs to return (max 100)
        - name: offset
          in: query
          required: false
          schema:
            type: integer
            default: 0
          description: Number of logs to skip (for pagination)
        - name: action
          in: query
          required: false
          schema:
            type: string
          description: Filter by audit action type (e.g., "USER_LOGIN", "PASSWORD_CHANGE")
      responses:
        '200':
          description: Audit logs
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuditLogsResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth: []
components:
  schemas:
    AuditLogsResponse:
      type: object
      properties:
        logs:
          type: array
          items:
            $ref: '#/components/schemas/AuditLog'
        total:
          type: integer
        limit:
          type: integer
        offset:
          type: integer
    Error:
      type: object
      required:
        - error
        - message
      properties:
        error:
          type: string
        message:
          type: string
    AuditLog:
      type: object
      properties:
        id:
          type: string
        action:
          type: string
        data:
          type: object
          additionalProperties: true
        createdAt:
          type: string
          format: date-time
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

````