Reputation: 404
I found that OpenIddictToken
has Properties
and Payload
fields. As I understand that can be populated by custom data which will be persisted in database but won't be send to client. But I can't find how should I write/read these properties? I saw that I can provide custom properties to AuthenticationTicket
but it seems to be completely different properties.
What is the right way to work with these properties?
Upvotes: 1
Views: 1284
Reputation: 404
Really it looks like really weird behavior of OpenIddictAuthorizationManager
specifically PopulateAsync
function:
await Store.SetApplicationIdAsync(authorization, descriptor.ApplicationId, cancellationToken);
await Store.SetScopesAsync(authorization, ImmutableArray.CreateRange(descriptor.Scopes), cancellationToken);
await Store.SetStatusAsync(authorization, descriptor.Status, cancellationToken);
await Store.SetSubjectAsync(authorization, descriptor.Subject, cancellationToken);
await Store.SetTypeAsync(authorization, descriptor.Type, cancellationToken);
it populates everything except properties. So here what I did to persist properties in database. First I added properties I need in authorization phase /connect/authorize
:
var ticket = new AuthenticationTicket(
principal,
new AuthenticationProperties(new Dictionary<string, string>{ { "name", "value" } }),
OpenIddictServerDefaults.AuthenticationScheme);
then as suggested in an answer above I made my own tiny auth manager:
public class AuthorizationManager<TAuthorization>: OpenIddictAuthorizationManager<TAuthorization> where TAuthorization : OpenIddict.MongoDb.Models.OpenIddictAuthorization
{
public AuthorizationManager(...): base(cache, resolver, logger, options)
{
}
public async override Task PopulateAsync(
[NotNull] TAuthorization authorization,
[NotNull] OpenIddictAuthorizationDescriptor descriptor,
CancellationToken cancellationToken = default)
{
await base.PopulateAsync(authorization, descriptor, cancellationToken);
if (descriptor.Properties.Any())
{
authorization.Properties = new MongoDB.Bson.BsonDocument(
descriptor.Properties.Where(p => p.Key[0] != '.') // skip scopes and other technical fields
.Select(p => new MongoDB.Bson.BsonElement(p.Key, p.Value))
);
}
}
}
where I populated all the properties. And finally I just enabled my manager:
options.ReplaceAuthorizationManager<Services.OpenId.AuthorizationManager<OpenIddictAuthorization>>();
Upvotes: 0
Reputation: 42070
The Properties
column - common to all OpenIddict entities - is indeed meant to be used as a generic bag for non-essential properties, which allows storing data without having to change the schema. Properties are not directly accessible using the default managers. Instead, you're encouraged to create your own manager derived from the built-in one and use Store.GetPropertiesAsync()
/Store.SetPropertiesAsync()
to access the properties.
OrchardCore's OpenID module has a custom application manager that uses it to store application roles so you can take a look at the source code to see how they are used: https://github.com/OrchardCMS/OrchardCore/blob/dev/src/OrchardCore/OrchardCore.OpenId.Core/Services/Managers/OpenIdApplicationManager.cs#L86-L92
Note: in OpenIddict 3.0, Store.GetPropertiesAsync()
/Store.SetPropertiesAsync()
were updated to use System.Text.Json
instead of JSON.NET.
The Payload
column is used to store reference tokens and is not meant to be used to store additional data.
It's worth noting that there's a simple option if you want to store data that will be kept private: if you don't add the access token/identity token destinations to your private claims, they won't be persisted in access/identity tokens and will only be present in the authorization codes/refresh tokens, that are always encrypted and can't be read by the client.
Upvotes: 1