options.AddPolicy("Account", policy => policy.RequireClaim(JwtClaimTypes.Scope, "account"));
options.AddPolicy("AccountWrite", policy => policy.RequireClaim(JwtClaimTypes.Scope, "account.write"));
options.AddPolicy("AccountRead", policy => policy.RequireClaim(JwtClaimTypes.Scope, "account.read"));
How do you add an OR to a policy scope?
To answer your question, you can add multiple arguments to the RequireClaim statement. As documented:
RequireClaim(String, String[])
claimType String
The claim type required.
allowedValues IEnumerable
Values the claim must process one or more of for evaluation to succeed.
In your case something like:
options.AddPolicy("Account", policy =>
policy.RequireClaim(JwtClaimTypes.Scope, "account", "account.read", "account.write", "account.delete"));
options.AddPolicy("AccountWrite", policy =>
policy.RequireClaim(JwtClaimTypes.Scope, "account", "account.write"));
options.AddPolicy("AccountRead", policy =>
policy.RequireClaim(JwtClaimTypes.Scope, "account", "account.read"));
But this is a bit odd for scopes.
Having a scope means that a client is authorized to access the resource, regardless which user uses the client.
A scope marks a part of the resource that does a specific task, in other words, has certain functionality.
Assuming a CRUD AccountController:
You can authorize a client to access the entire controller, use the account
scope in that case on top of the controller.
You can authorize the client per method, e.g. account.read
the Index method, account.write
the Create and Update methods and account.delete
the Delete method. It's not likely that scopes can be mixed due to the difference in functionality.
Both can be fine, because it's the user that needs to be authorized to use the resource. The client takes the user to the resource and does the request on behalf of the user. But it makes no sense to combine both.
What would be the appropriate design for you?
Suppose you have an admin app, where the user is allowed to manage the account. The customer has its own app and wants to access the resource using that app, but you don't want to allow full management from that app.
In that case the client app from the customer should be allowed to request the account.read
scope only. Because, if the user is allowed to manage the account, then you want to make sure that this is only possible using your app.
So you can 'normalize' the policies.
For 1.
options.AddPolicy("Account", policy =>
policy.RequireClaim(JwtClaimTypes.Scope, "account"));
and for 2.
options.AddPolicy("AccountDelete", policy =>
policy.RequireClaim(JwtClaimTypes.Scope, "account.delete"));
options.AddPolicy("AccountWrite", policy =>
policy.RequireClaim(JwtClaimTypes.Scope, "account.write"));
options.AddPolicy("AccountRead", policy =>
policy.RequireClaim(JwtClaimTypes.Scope, "account.read"));
Come to think of it, based on the customer app as mentioned above, there is a third option:
AccountRead
the Index method and Account
for the other methods. Where AccountRead
must include the account scope.The policies would then look like:
// policy to allow client access to write and delete functionality
options.AddPolicy("Account", policy =>
policy.RequireClaim(JwtClaimTypes.Scope, "account"));
// policy to allow client access to read functionality only
options.AddPolicy("AccountRead", policy =>
policy.RequireClaim(JwtClaimTypes.Scope, "account", "account.read"));
The admin app only has to request the account
scope, while the customer app can request the account.read
scope.
Please note that the last part does not answer your original question but may answer the questions raised in the comments.