> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/WalysonGomes/secure-link-api/llms.txt
> Use this file to discover all available pages before exploring further.

# Password Protection

> Learn how to protect links with passwords and handle authentication

## Overview

Password protection adds an additional security layer to your links. When a link is password-protected, users must provide the correct password via the `X-Link-Password` header to access the resource.

## Creating Password-Protected Links

Include the `password` parameter when creating a link:

<Tabs>
  <Tab title="URL Links">
    ```bash theme={null}
    curl -X POST http://localhost:8080/api/links \
      -H "Content-Type: application/json" \
      -d '{
        "targetUrl": "https://example.com/secure",
        "password": "MySecurePassword123"
      }'
    ```

    Response:

    ```json theme={null}
    {
      "shortCode": "abc123",
      "accessUrl": "http://localhost:8080/l/abc123",
      "expiresAt": null,
      "maxViews": null
    }
    ```
  </Tab>

  <Tab title="File Uploads">
    ```bash theme={null}
    curl -X POST http://localhost:8080/api/links/upload \
      -F "file=@confidential.pdf" \
      -F "password=FilePass456"
    ```

    Response:

    ```json theme={null}
    {
      "shortCode": "xyz789",
      "accessUrl": "http://localhost:8080/l/xyz789",
      "expiresAt": null,
      "maxViews": null
    }
    ```
  </Tab>
</Tabs>

<Note>
  Passwords are hashed using BCrypt before storage. The plain-text password is never stored on the server.
</Note>

## Accessing Password-Protected Links

To access a password-protected link, include the `X-Link-Password` header in your request.

### For URL Redirects

<CodeGroup>
  ```bash cURL theme={null}
  curl -L http://localhost:8080/l/abc123 \
    -H "X-Link-Password: MySecurePassword123"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('http://localhost:8080/l/abc123', {
    headers: {
      'X-Link-Password': 'MySecurePassword123'
    },
    redirect: 'follow'
  });
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      'http://localhost:8080/l/abc123',
      headers={'X-Link-Password': 'MySecurePassword123'},
      allow_redirects=True
  )
  ```
</CodeGroup>

### For File Downloads

```bash theme={null}
curl -L http://localhost:8080/l/xyz789 \
  -H "X-Link-Password: FilePass456" \
  -o downloaded-file.pdf
```

### Getting JSON Response Instead of Redirect

For URL redirects, you can request JSON format by setting the `Accept` header:

```bash theme={null}
curl http://localhost:8080/l/abc123 \
  -H "X-Link-Password: MySecurePassword123" \
  -H "Accept: application/json"
```

Response:

```json theme={null}
{
  "type": "REDIRECT",
  "targetUrl": "https://example.com/secure"
}
```

## Password Validation Flow

The password authentication follows this sequence:

<Steps>
  <Step title="Request received">
    The server receives a request to `/l/{shortCode}` with the `X-Link-Password` header.
  </Step>

  <Step title="Link lookup">
    The server finds the link by short code and checks if it's password-protected.
  </Step>

  <Step title="Password required check">
    If the link is password-protected but no password header is provided, a 401 Unauthorized response is returned.
  </Step>

  <Step title="Password validation">
    The provided password is compared against the stored BCrypt hash using `PasswordEncoder.matches()`.
  </Step>

  <Step title="Access granted or denied">
    * If the password matches: Access is granted and the resource is returned
    * If the password is incorrect: 401 Unauthorized is returned
  </Step>
</Steps>

## Error Responses

### Missing Password

When accessing a password-protected link without providing the password:

```bash theme={null}
curl -L http://localhost:8080/l/abc123
```

Response (401 Unauthorized):

```json theme={null}
{
  "timestamp": "2026-03-04T14:30:00Z",
  "status": 401,
  "error": "Unauthorized",
  "message": "Password required",
  "path": "/l/abc123"
}
```

### Invalid Password

When providing an incorrect password:

```bash theme={null}
curl -L http://localhost:8080/l/abc123 \
  -H "X-Link-Password: WrongPassword"
```

Response (401 Unauthorized):

```json theme={null}
{
  "timestamp": "2026-03-04T14:30:00Z",
  "status": 401,
  "error": "Unauthorized",
  "message": "Invalid password",
  "path": "/l/abc123"
}
```

<Warning>
  Password validation occurs before other access checks like expiration and view limits. This prevents attackers from using timing attacks to determine if a link exists.
</Warning>

## Security Implementation Details

The password protection implementation (from ResolveLinkServiceImpl:87-94):

```java theme={null}
if (link.isPasswordProtected()) {
  if (password == null || password.isBlank()) {
    handleDenied(link.getShortCode(), AccessResult.PASSWORD_REQUIRED, 
      "password_required", HttpStatus.UNAUTHORIZED, "Password required", context);
  }
  if (!passwordEncoder.matches(password, link.getPasswordHash())) {
    handleDenied(link.getShortCode(), AccessResult.INVALID_PASSWORD, 
      "invalid_password", HttpStatus.UNAUTHORIZED, "Invalid password", context);
  }
}
```

### Security Features

<AccordionGroup>
  <Accordion title="BCrypt Password Hashing" icon="shield-halved">
    Passwords are hashed using BCrypt, a strong adaptive hash function designed for password storage. This prevents password exposure even if the database is compromised.
  </Accordion>

  <Accordion title="Audit Logging" icon="clipboard-list">
    All password attempts are logged with the result:

    * `PASSWORD_REQUIRED` - No password provided
    * `INVALID_PASSWORD` - Wrong password
    * `SUCCESS` - Correct password

    This helps detect brute-force attacks.
  </Accordion>

  <Accordion title="Secure Header Transmission" icon="lock">
    The `X-Link-Password` header should be transmitted over HTTPS to prevent password interception. Never send passwords over unencrypted HTTP connections in production.
  </Accordion>

  <Accordion title="No Password in URL" icon="eye-slash">
    Passwords are never included in the URL or query parameters, preventing exposure in browser history, server logs, and referrer headers.
  </Accordion>
</AccordionGroup>

## Best Practices

### Password Strength

<CodeGroup>
  ```bash Strong Password theme={null}
  curl -X POST http://localhost:8080/api/links \
    -H "Content-Type: application/json" \
    -d '{
      "targetUrl": "https://example.com/secure",
      "password": "xK9$mP2!qL5#nR8@"
    }'
  ```

  ```bash Weak Password (Avoid) theme={null}
  curl -X POST http://localhost:8080/api/links \
    -H "Content-Type: application/json" \
    -d '{
      "targetUrl": "https://example.com/secure",
      "password": "password123"
    }'
  ```
</CodeGroup>

<Note>
  Use strong passwords with a mix of uppercase, lowercase, numbers, and special characters. Consider generating passwords programmatically for maximum security.
</Note>

### Recommended Practices

* **Use HTTPS in production**: Always transmit passwords over encrypted connections
* **Generate strong passwords**: Use cryptographically secure random password generators
* **Communicate passwords securely**: Send passwords to users through separate channels (e.g., email the link, SMS the password)
* **Combine with expiration**: Use both password protection and expiration for maximum security
* **Monitor failed attempts**: Set up alerts for excessive failed password attempts
* **Rotate passwords**: For long-lived links, consider periodic password rotation

### Example: Secure Link Creation with All Protections

```bash theme={null}
curl -X POST http://localhost:8080/api/links/upload \
  -F "file=@financial-report-2026.pdf" \
  -F "password=xK9$mP2!qL5#nR8@" \
  -F "expiresAt=2026-03-31T23:59:59+00:00" \
  -F "maxViews=3"
```

This creates a download link that:

* Requires a strong password
* Expires on March 31, 2026
* Can only be downloaded 3 times

## Testing Password Protection

Here's a complete example workflow:

<Steps>
  <Step title="Create a password-protected link">
    ```bash theme={null}
    curl -X POST http://localhost:8080/api/links \
      -H "Content-Type: application/json" \
      -d '{
        "targetUrl": "https://example.com/test",
        "password": "TestPass123"
      }'
    ```
  </Step>

  <Step title="Test without password (should fail)">
    ```bash theme={null}
    curl -v http://localhost:8080/l/abc123
    ```

    Expected: 401 Unauthorized with "Password required"
  </Step>

  <Step title="Test with wrong password (should fail)">
    ```bash theme={null}
    curl -v http://localhost:8080/l/abc123 \
      -H "X-Link-Password: WrongPassword"
    ```

    Expected: 401 Unauthorized with "Invalid password"
  </Step>

  <Step title="Test with correct password (should succeed)">
    ```bash theme={null}
    curl -L http://localhost:8080/l/abc123 \
      -H "X-Link-Password: TestPass123"
    ```

    Expected: 302 redirect to [https://example.com/test](https://example.com/test)
  </Step>
</Steps>

## Next Steps

<CardGroup cols={2}>
  <Card title="Link Expiration" icon="clock" href="/guides/link-expiration">
    Combine passwords with expiration settings
  </Card>

  <Card title="Creating Links" icon="link" href="/guides/creating-links">
    Learn all link creation options
  </Card>

  <Card title="Uploading Files" icon="upload" href="/guides/uploading-files">
    Password-protect file downloads
  </Card>

  <Card title="Security Metrics" icon="chart-line" href="/api/stats/security-metrics">
    Monitor password attempt patterns
  </Card>
</CardGroup>
