Create the dictionary
Use the data from your business requirements and authorization use cases to define relevant attributes in an attribute dictionary document. A well-structured attribute dictionary enhances communication among stakeholders, including internal teams, PIP owners, and auditors.
The attribute dictionary document is a design document for people, kept wherever your team keeps its documentation. It is not read by APD. For example:
| Namespace and name | Category | Type | Source | Key | Responsible/SLA | Cardinality | Reference | Description | Examples |
|---|---|---|---|---|---|---|---|---|---|
acme.user.identity | subject | string | PEP | - | - | 1..1 | HR AD, 6 character alphanum | Acme employee signature | johsmi, jandoe |
acme.customer.identity | resource | string | PEP | - | - | 0..* | Salesforce customer id | Customer(s) involved in action | 231698, 249111 |
acme.customer.location | resource | string | Salesforce customer PIP | acme.customer.identity | Business Operation team, 99% | 0..* | ISO 3166-1 | Customer origin country | SE, US |
In the Source column, PEP (Policy Enforcement Point) means that the application asking for the access decision sends the attribute in the request. A PIP means that an attribute connector retrieves it.
id is a reserved word in ALFA and can not be used in attribute names. For a full list of reserved words, see the Attribute identifiersOpens in a new tab section of the Access Decision Service (ADS) documentation.
Define the attributes
Before using attributes in ALFA policies, JUnit tests, or attribute connectors, define them in src/authorizationDomain/attributes.yaml. attributes.yaml is the authoritative attribute dictionary: ADS reads it, and you generate the ALFA dictionary for the policies and the Java dictionary for the tests from it. Do not edit the generated files.
When you replace the sample of the APD distribution with your own authorization domain, delete its attributes together with its policies and tests.
Workflow:
-
Add attributes in
src/authorizationDomain/attributes.yaml. -
Generate the ALFA and Java dictionaries by running:
./gradlew generateAlfaDictionaryFromYaml generateJavaDictionaryFromYamlAlternatively, you can run these tasks from your IDE's Gradle tool window under the
axiomatics-dictionarygroup. -
The generated dictionary files will be located at
src/authorizationDomain/alfaSpecifications/attributes.alfaandsrc/test/java/apd/Dictionary.java. These should be committed to your repository as normal files.
The generate tasks do not overwrite a dictionary file that has uncommitted changes, so that no change is lost: they fail and tell you to commit or stash the changes first. To overwrite the file anyway, add -Dapd.allowUnsafe=true.
To generate the dictionaries automatically when you run the tests or build the domain, add to build.gradle:
tasks.named('test') { dependsOn 'generateAlfaDictionaryFromYaml', 'generateJavaDictionaryFromYaml' }
tasks.named('buildAuthzDomain') { dependsOn 'generateAlfaDictionaryFromYaml' }
Commit the generated files together with attributes.yaml.
If you use Authorization Hub, you can also create the dictionary in Authorization Hub and pull it using DictionaryPullFrom{environment}. This merges the attributes into attributes.yaml: attributes in both get the values from Authorization Hub, attributes only in Authorization Hub are added, and attributes only in the file are kept. Then run generateAlfaDictionaryFromYaml and generateJavaDictionaryFromYaml to update the ALFA and Java dictionaries (or run AllPullFrom{environment}, which executes both). For details, see Authorization Hub integration.
Organize your attributes into hierarchical namespaces as needed:
acme.user.role:
xacmlId: acme.user.role
category: AccessSubject
datatype: string
acme.user.location:
xacmlId: acme.user.location
category: AccessSubject
datatype: string
acme.resource.location:
xacmlId: acme.resource.location
category: Resource
datatype: string
- For the attributes above,
acme.userandacme.resourceare namespaces, androle,locationandlocationare names. - Set
xacmlIdto the attribute name (the first-level YAML key). See the warning below for the exception. categorycan beAccessSubject,Resource,ActionorEnvironmentand it specifies whether the attribute is a property of a subject (for example, role), resource (for example, owner), etc. See Choosing a category below for guidance.datatypeshould be one of the JSON shorthand type codes listed in section 3.3.1 Supported Data TypesOpens in a new tab of the JSON Profile of XACML 3.0 Version 1.0 specification.
Keeping the attribute name and xacmlId the same minimizes the risk of typos and mistakes. If you already have policies in production following the XACML standard of having attribute ids as URNs, there is a chance your attribute ids contain the : character. This character is not valid in the YAML dictionary. In such case, leave xacmlId to your original attribute ID and choose a new attribute name. Then, you must also disable the APD check that validates names and ids are equal:
alfa {
extraAttributeIdCheck false
}
Choosing a category
The category tells ADS how to group and match attributes in an authorization request. Choosing the right category is important because an attribute sent under the wrong category will not match the corresponding policy condition.
Use the following decision rule:
| Ask yourself | Category |
|---|---|
| Who is performing the action? (user, service, system) | AccessSubject |
| What is being accessed? (document, record, endpoint, file) | Resource |
| What action is being performed? (read, write, approve, delete) | Action |
| What is independent of all parties? (current time, date, day of week) | Environment |
Examples:
| Attribute | Category | Reason |
|---|---|---|
user.role | AccessSubject | It is a property of the user making the request |
user.location | AccessSubject | It is a property of the user: where they are located |
user.ip_address | AccessSubject | It is a property of the requesting client |
user.risk_score | AccessSubject | It is a computed property of the user's session or identity |
resource.classification | Resource | It is a property of the thing being accessed |
resource.owner | Resource | It describes ownership of the accessed item |
action.name | Action | It describes what operation is being requested |
When in doubt, AccessSubject and Resource cover the vast majority of real-world ABAC attributes. Environment is reserved for attributes that are truly independent of all parties (typically time and date). Action is used when policy decisions depend on what operation is being performed, not just who or what.
Date and time
ADS provides three standard XACML environment attributes for the current date and time automatically on every authorization request, which you do not need to define in attributes.yaml:
| XACML attribute ID | ALFA name | Type |
|---|---|---|
urn:oasis:names:tc:xacml:1.0:environment:current-time | currentTime | time |
urn:oasis:names:tc:xacml:1.0:environment:current-date | currentDate | date |
urn:oasis:names:tc:xacml:1.0:environment:current-dateTime | currentDateTime | dateTime |
You can use these directly in ALFA policies. ADS resolves them from its clock. To make a test independent of when it runs, set the current time in the test with the XACML id. For example, to test a policy that permits when user.employment.started (a date attribute in attributes.yaml) is in the current year:
.with("user.employment.started", "2026-03-01")
.with("urn:oasis:names:tc:xacml:1.0:environment:current-date", "2026-10-28")
Use the XACML id, not the attribute name from attributes.yaml: with the name, the test sends a different attribute id, and the policy uses the clock instead.