AD doesn't let users add custom claims. So the feature request is if we can add a mapping configuration, which maps existing claims of AD JWT to hasura session variables.
Hasura requires a default/current role and a list of allowed roles for the user. Other session variables are based on the permissions defined by the user.
So we can introduce a new key in the existing JWT config -
{
"claims_map": {
"x-hasura-default-role": "<existing-JWT-claim-json-path>",
"x-hasura-allowed-roles": "<existing-JWT-claim-json-path>",
"x-hasura-custom-stuff-1": "<existing-JWT-claim-json-path>",
"x-hasura-custom-stuff-2": "<existing-JWT-claim-json-path>"
}
}
The x-hasura-default-role and x-hasura-allowed-roles are mandatory fields. The other ones are optional. And only the value of x-hasura-allowed-roles is a list of strings, and everything else is a string.
If Hasura sees this inside the JWT config, then it will use this over the hardcoded values for the roles. For the other stuff, Hasura looks for claims starting with x-hasura-, that will change and Hasura will only lookup values from this map.
Relevant resources:
https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-optional-claims
https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-claims-mapping
I've started working on something like this but admit Haskell is brand new to me. I started going down the path of having a config value for defaultClaimPrefix (e.g., to override x-hasura-*, ideally with empty string just making the whole claimset available) and allowedRoleClaimName to map the azure roles claim to the hasura allowed roles claim - driven by appRoles in Azure AD.
Where I'm struggling is in processAuthZHeader, here - I'm trying to get all claims from the token in the event there is no prefix, but unfamiliarity with haskell is killing me.
Anyway - great to see this is under consideration, I have multiple customers looking for this and happy to support however I can.
I just went through a couple months long process of back and forth with Azure support on this topic as well. We went so far as to speak with their engineering teams. In the end, they conceded that it was not possible for them to implement complex custom claims through JWTs on Azure Active Directory.
Microsoft does not have the technical expertise to implement configurable complex custom claims on JWTs with their Azure Active Directory platform despite being listed as an author on RFC 7519 - see Appendix C. Relationship of JWTs to Simple Web Tokens (SWTs) on page 29:
For SWTs, both the claim names and claim values are strings. For JWTs, while claim names are strings, claim values can be any JSON type.
Microsoft is only able to support string values for JWTs, not JSON types as the specification defines.
@Oxymoron290 thanks for the info.
As you can see this is the RFC for the implementation. It is already implemented in https://github.com/hasura/graphql-engine/pull/3575 , and we are testing it out currently.
Suggesting a small change to the RFC for better configurability for non-customizable JWTs:
{
"claims_map": {
"x-hasura-default-role": <string> | <pathOrDefault>, #required
"x-hasura-allowed-roles": <string> | <pathOrDefault>, #required
"x-hasura-custom-stuff-1": <string> | <pathOrDefault>, #optional
"x-hasura-custom-stuff-2": <string> | <pathOrDefault> #optional
}
}
The schema of pathOrDefault looks like this:
{
"path": "<existing-JWT-claim-json-path>", # required
"default": <string> # optional
}
Regarding the behaviour (because now we have either string or pathOrDefault ):
string is given, then it is taken as a literal value of the session variablepathOrDefault is given, then a value is peeked at the path and if nothing is found default is used.claims_map is provided then no other session variables (i.e. keys starting with x-hasura-) are read from the jwt i.e. claims_namespace is ignored. This is for simplicity. If later we have a situation where some keys are to be used from the claims_namespace, then we can merge it with some prioritization for conflicting keys.Since, this issue allows for better compatibility of JWTs in general (not just Azure AD), I am changing the title of this to reflect the same.
Implementation note:
default in pathOrDefault for the first version.This works great for mapping claims from an Azure AD token so far, would love to see the "default" part get implemented because I want to fall back to a default role when there isn't one in the token.
The PR is working for me too! Thanks for this.
I could also use the default feature to handle a default role. :+1:
Most helpful comment
Suggesting a small change to the RFC for better configurability for non-customizable JWTs:
The schema of
pathOrDefaultlooks like this:Regarding the behaviour (because now we have either
stringorpathOrDefault):stringis given, then it is taken as a literal value of the session variablepathOrDefaultis given, then a value is peeked at thepathand if nothing is founddefaultis used.claims_mapis provided then no other session variables (i.e. keys starting withx-hasura-) are read from the jwt i.e.claims_namespaceis ignored. This is for simplicity. If later we have a situation where some keys are to be used from theclaims_namespace, then we can merge it with some prioritization for conflicting keys.Since, this issue allows for better compatibility of JWTs in general (not just Azure AD), I am changing the title of this to reflect the same.
Implementation note:
defaultinpathOrDefaultfor the first version.