Legacy Note Delivery for Premium Users (Email-Based, No Bitwarden Account Required)

Hi Bitwarden Community,

I’d like to propose a new feature for Bitwarden Premium users that I believe could be a game-changer: a Legacy Note Delivery service. This would allow users to set up a simple note or message (e.g., a testament or final instructions) to be sent via email to designated contacts if their Bitwarden account remains inactive for a specified period, such as one year.

Unlike the existing Emergency Access feature, this Legacy Note Delivery would:

  • Not require recipients to have a Bitwarden account, making it accessible to anyone with an email address.
  • Be extremely simple for contacts to receive and understand, as it’s just a plain email with the note or instructions.
  • Focus on delivering a one-time message rather than granting vault access, catering to users who want to leave behind straightforward guidance or wishes.

I think this feature would be highly appealing for several reasons:

  1. It adds a unique, emotionally meaningful layer to Bitwarden’s offerings, addressing real-life concerns about legacy planning.
  2. Its simplicity makes it user-friendly for both the account holder and recipients.
  3. It could attract more users to Bitwarden Premium, as it’s a distinctive feature not commonly found in other password managers.

For example, a user could write a note with instructions like “My important documents are in X location” or “Please contact Y for my affairs,” and Bitwarden would securely store and deliver it to the chosen email addresses after a year of inactivity (with safeguards like confirmation emails to the user beforehand to prevent accidental triggers).

I’d love to hear your thoughts on this idea! Do you think it would be valuable? Any suggestions to refine it? I believe this could make Bitwarden stand out even more and encourage more people to upgrade to Premium.

Thanks

Since Bitwarden’s server uses C# with ASP.NET Core, here’s a rough idea for an endpoint to manage this. It follows your existing patterns with Entity Framework Core and JWT authentication. This could be a starting point for the team to build on:

// Model for the Legacy Note
public class LegacyNote
{
public int Id { get; set; }
public string UserId { get; set; } // Links to the user
public byte EncryptedNote { get; set; } // Encrypted content
public List RecipientEmails { get; set; } // Email list
public DateTime LastActivity { get; set; } // Tracks inactivity
}

// Db Context
using Microsoft.EntityFrameworkCore;

public class VaultContext : DbContext
{
public DbSet LegacyNotes { get; set; }

public VaultContext(DbContextOptions<VaultContext> options) : base(options) { }

}

// Repository
public interface ILegacyNoteRepository
{
Task GetLegacyNoteAsync(string userId);
Task UpdateLastActivityAsync(string userId, DateTime activity);
}

public class LegacyNoteRepository : ILegacyNoteRepository
{
private readonly VaultContext _context;

public LegacyNoteRepository(VaultContext context)
{
    _context = context;
}

public async Task<LegacyNote> GetLegacyNoteAsync(string userId)
{
    return await _context.LegacyNotes
        .FirstOrDefaultAsync(note => note.UserId == userId);
}

public async Task UpdateLastActivityAsync(string userId, DateTime activity)
{
    var note = await _context.LegacyNotes.FirstOrDefaultAsync(n => n.UserId == userId);
    if (note != null)
    {
        note.LastActivity = activity;
        await _context.SaveChangesAsync();
    }
}

}

// Controller with a scheduled job hint
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
using System.Threading.Tasks;

[Authorize]
[ApiController]
[Route(“api/[controller]”)]
public class LegacyNotesController : ControllerBase
{
private readonly ILegacyNoteRepository _repository;
private readonly ILogger _logger;

public LegacyNotesController(ILegacyNoteRepository repository, ILogger<LegacyNotesController> logger)
{
    _repository = repository;
    _logger = logger;
}

[HttpGet]
public async Task<ActionResult<LegacyNote>> GetLegacyNote()
{
    var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
    if (userId == null) return Unauthorized();

    var note = await _repository.GetLegacyNoteAsync(userId);
    return Ok(note);
}

[HttpPost("update-activity")]
public async Task<IActionResult> UpdateLastActivity()
{
    var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
    if (userId == null) return Unauthorized();

    await _repository.UpdateLastActivityAsync(userId, DateTime.UtcNow);
    return Ok();
}

}

// Note: A background service could check inactivity (e.g., every 24h):
// If LastActivity is > 1 year ago, trigger email sending via a secure SMTP service.

Notes on the code:
• The LegacyNote model stores the encrypted note and recipient emails, with LastActivity to track usage..