Skip to main content

Overview

Link revocation allows you to immediately disable access to a link, regardless of its expiration settings. This is useful when:
  • Content needs to be removed urgently
  • A link was shared with unintended recipients
  • Security concerns require immediate access termination
  • A password has been compromised
  • You need to rotate or update content
To revoke a link, send a DELETE request to /l/{shortCode}:
curl -X DELETE http://localhost:8080/l/abc123

Success Response

When revocation succeeds, you receive a 204 No Content response with an empty body:
HTTP/1.1 204 No Content
A 204 status code indicates the link was successfully revoked. No response body is returned.

Revocation Implementation

The revocation endpoint is defined in RevokeLinkController:
@DeleteMapping("/l/{shortCode}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void revoke(@PathVariable String shortCode){
  revokeLinkService.revoke(shortCode);
}
The service marks the link as revoked in the database and prevents all future access. Once revoked, any attempt to access the link will fail:
curl -L http://localhost:8080/l/abc123
Response (410 Gone):
{
  "timestamp": "2026-03-04T14:30:00Z",
  "status": 410,
  "error": "Gone",
  "message": "Link access denied",
  "path": "/l/abc123"
}
Revocation is permanent and cannot be undone. Once a link is revoked, it cannot be reactivated. You must create a new link if access needs to be restored.

Revocation Validation

From ResolveLinkServiceImpl:71-73, revocation is checked first:
if (link.isRevoked()) {
  handleDenied(link.getShortCode(), AccessResult.REVOKED, "revoked", context);
}
This check occurs before all other validations (expiration, password, view limits), ensuring revoked links are immediately inaccessible.

Error Handling

If the short code doesn’t exist:
curl -X DELETE http://localhost:8080/l/invalid123
Response (404 Not Found):
{
  "timestamp": "2026-03-04T14:30:00Z",
  "status": 404,
  "error": "Not Found",
  "message": "Link not found",
  "path": "/l/invalid123"
}

Already Revoked

Revoking an already-revoked link typically returns 204 No Content (idempotent operation). The link remains in the revoked state.

Complete Workflow Example

1

Create a link

curl -X POST http://localhost:8080/api/links \
  -H "Content-Type: application/json" \
  -d '{
    "targetUrl": "https://example.com/content",
    "expiresAt": "2027-12-31T23:59:59Z"
  }'
Response:
{
  "shortCode": "abc123",
  "accessUrl": "http://localhost:8080/l/abc123",
  "expiresAt": "2027-12-31T23:59:59Z",
  "maxViews": null
}
Important: Save the shortCode value for later revocation.
2

Verify link is accessible

curl -L http://localhost:8080/l/abc123
Expected: 302 redirect to https://example.com/content
3

Revoke the link

curl -X DELETE http://localhost:8080/l/abc123
Expected: 204 No Content
4

Verify link is now inaccessible

curl -L http://localhost:8080/l/abc123
Expected: 410 Gone with “Link access denied”

Use Cases

Emergency Content Removal

# Create link for a document
curl -X POST http://localhost:8080/api/links/upload \
  -F "[email protected]" \
  -F "expiresAt=2026-12-31T23:59:59Z"

# Later: Document contains error, must be removed immediately
curl -X DELETE http://localhost:8080/l/xyz789

Compromised Password

# Original password-protected link
curl -X POST http://localhost:8080/api/links \
  -H "Content-Type: application/json" \
  -d '{
    "targetUrl": "https://example.com/secure",
    "password": "OldPassword123",
    "expiresAt": "2026-12-31T23:59:59Z"
  }'

# Password leaked - revoke immediately
curl -X DELETE http://localhost:8080/l/abc123

# Create new link with new password
curl -X POST http://localhost:8080/api/links \
  -H "Content-Type: application/json" \
  -d '{
    "targetUrl": "https://example.com/secure",
    "password": "NewSecurePassword456",
    "expiresAt": "2026-12-31T23:59:59Z"
  }'

Content Rotation

# Revoke old version
curl -X DELETE http://localhost:8080/l/old123

# Upload new version
curl -X POST http://localhost:8080/api/links/upload \
  -F "[email protected]" \
  -F "expiresAt=2026-12-31T23:59:59Z"

Accidental Share

# Link accidentally shared in public channel
curl -X DELETE http://localhost:8080/l/abc123

# Create new link and share privately
curl -X POST http://localhost:8080/api/links \
  -H "Content-Type: application/json" \
  -d '{
    "targetUrl": "https://example.com/private-content",
    "password": "SecurePassword789",
    "maxViews": 10
  }'

Audit Trail

All access attempts to revoked links are logged in the audit system with AccessResult.REVOKED. This helps track:
  • When the link was revoked
  • Who attempted to access it after revocation
  • How many attempts were made
Check the audit logs or statistics endpoints for detailed information.

Best Practices

To enable revocation, you must store the shortCode value when creating links. Store it in your database with appropriate access controls.
// Example: Store in database
const response = await createLink({
  targetUrl: 'https://example.com/content',
  expiresAt: '2026-12-31T23:59:59Z'
});

await db.links.insert({
  shortCode: response.shortCode,
  accessUrl: response.accessUrl,
  createdAt: new Date(),
  purpose: 'Q4 Marketing Campaign'
});
If you’re building a user-facing application, expose revocation functionality through your UI:
  • Admin panel: Allow administrators to revoke any link
  • User dashboard: Let users revoke their own links
  • Automatic revocation: Implement triggers for suspicious activity
Clearly communicate to users:
  • Who can revoke links
  • Whether revocation is reversible (it’s not)
  • What happens to users who try to access revoked links
  • How to create replacement links
Track revocation metrics:
  • How many links are revoked manually vs. auto-expired
  • Average time between creation and revocation
  • Common reasons for revocation
This helps identify issues like:
  • Frequent password compromises
  • Incorrect expiration settings
  • User confusion about link management
If possible, notify users when a link they have access to is revoked:
// Example: Send notification after revocation
await revokeLink('abc123');

await sendEmail({
  to: affectedUsers,
  subject: 'Content Access Revoked',
  body: 'The link you received has been revoked. Please contact support for the updated link.'
});
The API marks links as revoked rather than deleting them. This preserves:
  • Audit trails for compliance
  • Statistics and analytics
  • Historical access attempts
Follow this pattern in your own data retention policies.

Revocation vs. Expiration

FeatureRevocationExpiration
TriggerManual API callAutomatic (time or views)
TimingImmediateScheduled or on view limit
ReversibleNoNo
Use caseEmergency removalPlanned lifecycle
Audit resultREVOKEDEXPIRED or VIEW_LIMIT_REACHED
Both revocation and expiration result in the same user experience (410 Gone), but they serve different purposes and are tracked separately in audit logs.

Security Considerations

Access Control

The current API doesn’t require authentication for revocation. In production, you should:
  1. Add authentication: Require API keys or OAuth tokens
  2. Implement authorization: Verify the requester owns the link
  3. Rate limiting: Prevent abuse of the revocation endpoint
  4. Audit logging: Log who revoked which links and when

Example: Protected Revocation Endpoint

# With authentication
curl -X DELETE http://localhost:8080/l/abc123 \
  -H "Authorization: Bearer your-api-token"

Prevention of Enumeration Attacks

To prevent attackers from discovering valid short codes:
  • Return consistent responses for revoked/expired/not-found links
  • Implement rate limiting on the revocation endpoint
  • Monitor for suspicious patterns (many failed revocation attempts)
  • Use longer, more complex short codes

Next Steps

Link Expiration

Learn about automatic expiration options

Creating Links

Understand all link creation options

Security Metrics

Monitor revocation and access patterns

Access Summary

View statistics on revoked links

Build docs developers (and LLMs) love