A library for ASP.NET Core that masks the timestamp portion of UUIDv7 using the UUIDv47 algorithm with reversible transformation.
This library uses UUIDv47Sharp (C# implementation) to reversibly mask GUIDs.
UUIDv47 is a reversible encoding format that hides the timestamp portion of UUIDv7.
- UUIDv7 → UUIDv47: XOR encryption with a 128-bit key to hide the timestamp
- Reversibility: The original UUIDv7 can be restored from UUIDv47 using the same key
- Key Management: Provide keys via
IMaskedUUIDKeyProvider(flexible support for different keys per tenant, etc.)
- uuidv47 - Go implementation (original)
- UUIDv47Sharp - C# implementation
UUIDv7 contains a 48-bit timestamp at the beginning, which means exposing it directly reveals the resource creation timestamp.
This poses the following information leakage risks:
- Business information such as user registration time and order time becomes guessable
- Growth rate and new user count leak to the outside
- Business status becomes visible to competitors
This library automatically performs UUIDv7 ↔ UUIDv47 conversion at the following timing:
- API Response:
MaskedGuidtype properties are converted to UUIDv47 when output to JSON - API Request: UUIDv47 strings are automatically restored to the original GUID when received
- URL Parameter: Accept UUIDv47 IDs in URLs like
/items/{id}with automatic restoration - SignalR: Automatic conversion of
MaskedGuidtype properties in Hub send/receive
MaskedGuidis masked (encoded/decoded) only during JSON input/output.MaskedGuid.ToString()returns the rawGuidstring (not the masked string).
MaskedGuidusesIMaskedUUIDServicefor masking during JSON conversion.Guid.Empty(empty GUID) becomesnullin JSON output.null/""(empty string) in JSON input is treated asGuid.Empty.
- JSON conversion for
MaskedGuidresolvesIMaskedUUIDServicefromHttpContext. - Therefore, JSON serialization/deserialization of
MaskedGuidoutside HTTP requests (background processing, non-Web environments) will throw an exception.
- URL/Query binding targets only
MaskedGuid/MaskedGuid?types. [MaskedUUID]attribute is not used (no attribute-based processing).MaskedGuid?is treated asnullwhen the decode result isGuid.Empty.MaskedGuidremains asGuid.Emptywhen the decode result isGuid.Empty.- In JSON conversion,
Guid.Emptyis output asnulland treated asGuid.Emptywhen read.
- In JSON conversion,
- Register
IMaskedUUIDKeyProvider - Register
IMaskedUUIDService - Add
AddMaskedUUID()andAddMaskedUUIDModelBinder()
See samples/MaskedUUID.Sample for samples.
// Register KeyProvider (Singleton recommended, Scoped also acceptable)
builder.Services.AddSingleton<IMaskedUUIDKeyProvider, MyKeyProvider>();
// Add MaskedUUID support
builder.Services.AddMaskedUUID();
// Add ModelBinder (for URL/query parameters)
mvcBuilder.AddMaskedUUIDModelBinder();
// Or all at once
mvcBuilder.AddMaskedUUIDControllers();Use the AddMaskedUUID() extension method for SignalR support.
// Register KeyProvider
builder.Services.AddSingleton<IMaskedUUIDKeyProvider, MyKeyProvider>();
// Add MaskedUUID support to SignalR
builder.Services.AddSignalR().AddMaskedUUID();SignalR converters resolve services in the following priority order:
- Hub Scope - Scope within Hub invocation (via HubFilter)
- HttpContext Scope - For HTTP connections
- Transient Scope - Fallback
This ensures correct operation whether KeyProvider/Service is Singleton / Scoped / Transient.
// Use reference keys for development/testing (do not use in production)
builder.Services.AddSignalR().AddMaskedUUIDWithReferenceKeys();Supports .NET 10+ and .NET 9.
// Add OpenAPI schema transformer
builder.Services.AddOpenApi(options => options.AddMaskedGuidSchemaTransformer());Automatically handles JsonSchemaType enum in .NET 10+ and string-based type specification in .NET 9.