I have started two development environment up with
dotnet watch run --urls=http://localhost:5001
command.
One instance is generating a PASETO token the other one is decoding it, the decoding instance fails with "Invalid Token".
I have used the following code with paseto-dotnet nuget package.
using System.Text.Json;
using FluentResults;
using Paseto;
using Paseto.Builder;
using Paseto.Cryptography.Key;
public static class TokenUtils
{
readonly static PasetoSymmetricKey pasetoSymmetricKey = new PasetoBuilder()
.UseV4(Purpose.Local)
.WithSharedKey(Encoding.UTF8.GetBytes("DummySecret"))
.GenerateSymmetricKey();
public static string GenerateLocalToken(TokenPayload tokenPayload)
{
return new PasetoBuilder()
.UseV4(Purpose.Local)
.WithKey(pasetoSymmetricKey)
.AddClaim("UserId", tokenPayload.AppId)
.IssuedAt(DateTime.UtcNow)
.Expiration(tokenPayload.ExpiresAt)
.Encode();
}
public static Result<TokenPayload> DecodeLocalToken(string token)
{
try
{
PasetoTokenValidationResult decodedResult = new PasetoBuilder()
.UseV4(Purpose.Local)
.WithSharedKey(Encoding.UTF8.GetBytes("DummySecret"))
.WithKey(pasetoSymmetricKey)
.Decode(token);
if (decodedResult is null) { return Result.Fail("Failed to Decode Token"); }
if (!decodedResult.IsValid) { return Result.Fail("Invalid Token"); }
TokenPayload? tokenPayload = JsonSerializer.Deserialize<TokenPayload>(decodedResult.Paseto.RawPayload);
if (tokenPayload is null) { return Result.Fail("Failed to Deserialize TokenPayload"); }
return Result.Ok(tokenPayload);
}
catch (Exception exception)
{
return Result.Fail(exception.Message);
}
}
}
using System.Text.Json.Serialization;
public class TokenPayload
{
public string UserId { get; set; } = default!;
[JsonPropertyName("iat")]
public DateTime IssuedAt { get; set; } = default!;
[JsonPropertyName("exp")]
public DateTime ExpiresAt { get; set; } = default!;
}
The GenerateSymmetricKey()
method is for generating a random symmetric key, regardless of the specified shared key. That's an issue from my side since I didn't clarify enough the use case of such method. I will update the code to reflect that.
Anyway, for passing a key to the PasetoBuilder
you should be using PASERK
. Currently, there's no quick way to create that so I will be adding a new method to the PasetoBuilder
.
In the meantime, for creating your own PasetoKey
using PASERK
, you can use the following code (for V4 Local in your case):
// I'm generating the key but you can supply your own, just make sure it has a length of 256 bits (32 bytes) which is required for V4 Local
var k = new byte[32];
RandomNumberGenerator.Fill(k);
var pasetoSymmetricKey = new PasetoSymmetricKey(k, new Version4());
var paserk = Paserk.Encode(pasetoSymmetricKey, PaserkType.Local);
So your code for decoding becomes:
var key = Paserk.Decode(paserk);
var decodedResult = new PasetoBuilder()
.UseV4(Purpose.Local)
.WithKey(key)
.Decode(token);
Update: Paseto.Core 1.1.1 has been published which includes the GenerateSerializedKey
method for serializing a Paseto Key in PASERK format.