Move documentation to keycloak-client

Closes #31870

Signed-off-by: rmartinc <rmartinc@redhat.com>
This commit is contained in:
rmartinc 2024-08-19 09:48:48 +02:00 committed by Marek Posolda
parent d21327445d
commit cce9ae94c7
15 changed files with 9 additions and 635 deletions

View file

@ -96,16 +96,4 @@ include::topics/service-rpt-overview.adoc[leveloffset=+2]
include::topics/service-rpt-token-introspection.adoc[leveloffset=+3]
include::topics/service-client-api.adoc[leveloffset=+2]
include::topics/enforcer-overview.adoc[leveloffset=+1]
include::topics/enforcer-configuration.adoc[leveloffset=+2]
include::topics/enforcer-claim-information-point.adoc[leveloffset=+2]
include::topics/enforcer-authorization-context.adoc[leveloffset=+2]
include::topics/enforcer-js-adapter.adoc[leveloffset=+2]
include::topics/enforcer-https.adoc[leveloffset=+2]
include::topics/enforcer-js-adapter.adoc[leveloffset=+1]

View file

@ -20,7 +20,7 @@ For more information, see <<_service_obtaining_permissions, Obtaining Permission
* **Policy Enforcement Point (PEP)**
+
Provides implementations for different environments to actually enforce authorization decisions at the resource server side.
{project_name} provides some built-in <<_enforcer_overview, Policy Enforcers>>.
{project_name} provides some built-in Policy Enforcers.
+
* **Policy Information Point (PIP)**
@ -78,7 +78,7 @@ what you want to protect (resource or scope) and the policies that must be satis
image:images/pep-pattern-diagram.png[alt="PEP overview"]
{project_name} provides some built-in <<_enforcer_overview, Policy Enforcers>> implementations that you can use to protect your applications depending on the platform they are running on.
{project_name} provides some built-in Policy Enforcers implementations that you can use to protect your applications depending on the platform they are running on.
== Authorization services

View file

@ -1,69 +0,0 @@
[[_enforcer_authorization_context]]
= Obtaining the authorization context
When policy enforcement is enabled, the permissions obtained from the server are available through `org.keycloak.AuthorizationContext`.
This class provides several methods you can use to obtain permissions and ascertain whether a permission was granted for a particular resource or scope.
Obtaining the Authorization Context in a Servlet Container
[source,java]
----
HttpServletRequest request = // obtain javax.servlet.http.HttpServletRequest
AuthorizationContext authzContext = (AuthorizationContext) request.getAttribute(AuthorizationContext.class.getName());
----
[NOTE]
The authorization context helps give you more control over the decisions made and returned by the server. For example, you can use it
to build a dynamic menu where items are hidden or shown depending on the permissions associated with a resource or scope.
[source,java]
----
if (authzContext.hasResourcePermission("Project Resource")) {
// user can access the Project Resource
}
if (authzContext.hasResourcePermission("Admin Resource")) {
// user can access administration resources
}
if (authzContext.hasScopePermission("urn:project.com:project:create")) {
// user can create new projects
}
----
The `AuthorizationContext` represents one of the main capabilities of {project_name} Authorization Services. From the examples above, you can see that the protected resource is not directly associated with the policies that govern them.
Consider some similar code using role-based access control (RBAC):
[source,java]
----
if (User.hasRole('user')) {
// user can access the Project Resource
}
if (User.hasRole('admin')) {
// user can access administration resources
}
if (User.hasRole('project-manager')) {
// user can create new projects
}
----
Although both examples address the same requirements, they do so in different ways. In RBAC, roles only _implicitly_ define access for their resources. With {project_name}, you gain the capability to create more manageable code that focuses directly on your resources whether you are using RBAC, attribute-based access control (ABAC), or any other BAC variant. Either you have the permission for a given resource or scope, or you do not have that permission.
Now, suppose your security requirements have changed and in addition to project managers, PMOs can also create new projects.
Security requirements change, but with {project_name} there is no need to change your application code to address the new requirements. Once your application is based on the resource and scope identifier, you need only change the configuration of the permissions or policies associated with a particular resource in the authorization server. In this case, the permissions and policies associated with the `Project Resource` and/or the scope `urn:project.com:project:create` would be changed.
= Using the AuthorizationContext to obtain an Authorization Client Instance
The ```AuthorizationContext``` can also be used to obtain a reference to the <<_service_client_api, Authorization Client API>> configured to your application:
[source,java]
----
ClientAuthorizationContext clientContext = ClientAuthorizationContext.class.cast(authzContext);
AuthzClient authzClient = clientContext.getClient();
----
In some cases, resource servers protected by the policy enforcer need to access the APIs provided by the authorization server. With an ```AuthzClient``` instance in hands, resource servers can interact with the server in order to create resources or check for specific permissions programmatically.

View file

@ -1,179 +0,0 @@
[[_enforcer_claim_information_point]]
= Claim Information Point
A Claim Information Point (CIP) is responsible for resolving claims and pushing these claims to the {project_name} server
in order to provide more information about the access context to policies. They can be defined as a configuration option
to the policy-enforcer in order to resolve claims from different sources, such as:
* HTTP Request (parameters, headers, body, etc)
* External HTTP Service
* Static values defined in configuration
* Any other source by implementing the Claim Information Provider SPI
When pushing claims to the {project_name} server, policies can base decisions not only on who a user is but also by taking
context and contents into account, based on who, what, why, when, where, and which for a given transaction. It is all about
Contextual-based Authorization and how to use runtime information in order to support fine-grained authorization decisions.
== Obtaining information from the HTTP request
Here are several examples showing how you can extract claims from an HTTP request:
.keycloak.json
[source,json]
----
{
"paths": [
{
"path": "/protected/resource",
"claim-information-point": {
"claims": {
"claim-from-request-parameter": "{request.parameter['a']}",
"claim-from-header": "{request.header['b']}",
"claim-from-cookie": "{request.cookie['c']}",
"claim-from-remoteAddr": "{request.remoteAddr}",
"claim-from-method": "{request.method}",
"claim-from-uri": "{request.uri}",
"claim-from-relativePath": "{request.relativePath}",
"claim-from-secure": "{request.secure}",
"claim-from-json-body-object": "{request.body['/a/b/c']}",
"claim-from-json-body-array": "{request.body['/d/1']}",
"claim-from-body": "{request.body}",
"claim-from-static-value": "static value",
"claim-from-multiple-static-value": ["static", "value"],
"param-replace-multiple-placeholder": "Test {keycloak.access_token['/custom_claim/0']} and {request.parameter['a']}"
}
}
}
]
}
----
== Obtaining information from an external HTTP service
Here are several examples showing how you can extract claims from an external HTTP Service:
.keycloak.json
[source,json]
----
{
"paths": [
{
"path": "/protected/resource",
"claim-information-point": {
"http": {
"claims": {
"claim-a": "/a",
"claim-d": "/d",
"claim-d0": "/d/0",
"claim-d-all": [
"/d/0",
"/d/1"
]
},
"url": "http://mycompany/claim-provider",
"method": "POST",
"headers": {
"Content-Type": "application/x-www-form-urlencoded",
"header-b": [
"header-b-value1",
"header-b-value2"
],
"Authorization": "Bearer {keycloak.access_token}"
},
"parameters": {
"param-a": [
"param-a-value1",
"param-a-value2"
],
"param-subject": "{keycloak.access_token['/sub']}",
"param-user-name": "{keycloak.access_token['/preferred_username']}",
"param-other-claims": "{keycloak.access_token['/custom_claim']}"
}
}
}
}
]
}
----
== Static claims
.keycloak.json
[source,json]
----
{
"paths": [
{
"path": "/protected/resource",
"claim-information-point": {
"claims": {
"claim-from-static-value": "static value",
"claim-from-multiple-static-value": ["static", "value"]
}
}
}
]
}
----
== Claim information provider SPI
The Claim Information Provider SPI can be used by developers to support different claim information points in case none of the
built-ins providers are enough to address their requirements.
For example, to implement a new CIP provider you need to implement `org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory`
and `ClaimInformationPointProvider` and also provide the file `META-INF/services/org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory`
in your application`s classpath.
Example of `org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory`:
[source,java]
----
public class MyClaimInformationPointProviderFactory implements ClaimInformationPointProviderFactory<MyClaimInformationPointProvider> {
@Override
public String getName() {
return "my-claims";
}
@Override
public void init(PolicyEnforcer policyEnforcer) {
}
@Override
public MyClaimInformationPointProvider create(Map<String, Object> config) {
return new MyClaimInformationPointProvider(config);
}
}
----
Every CIP provider must be associated with a name, as defined above in the `MyClaimInformationPointProviderFactory.getName` method. The name
will be used to map the configuration from the `claim-information-point` section in the `policy-enforcer` configuration to the implementation.
When processing requests, the policy enforcer will call the MyClaimInformationPointProviderFactory.create method in order to obtain an
instance of MyClaimInformationPointProvider. When called, any configuration defined for this particular CIP provider
(via claim-information-point) is passed as a map.
Example of `ClaimInformationPointProvider`:
[source,java]
----
public class MyClaimInformationPointProvider implements ClaimInformationPointProvider {
private final Map<String, Object> config;
public MyClaimInformationPointProvider(Map<String, Object> config) {
this.config = config;
}
@Override
public Map<String, List<String>> resolve(HttpFacade httpFacade) {
Map<String, List<String>> claims = new HashMap<>();
// put whatever claim you want into the map
return claims;
}
}
----

View file

@ -1,132 +0,0 @@
[[_enforcer_configuration]]
= Configuration
The policy enforcer configuration uses a JSON format and most of the time you don't need to set anything if you want to
automatically resolve the protected paths based on the resources available from your resource server.
If you want to manually define the resources being protected, you can use a slightly more verbose format:
[source,json]
----
{
"enforcement-mode" : "ENFORCING",
"paths": [
{
"path" : "/users/*",
"methods" : [
{
"method": "GET",
"scopes" : ["urn:app.com:scopes:view"]
},
{
"method": "POST",
"scopes" : ["urn:app.com:scopes:create"]
}
]
}
]
}
----
The following is a description of each configuration option:
* *enforcement-mode*
+
Specifies how policies are enforced.
+
** *ENFORCING*
+
(default mode) Requests are denied by default even when no policy is associated with a given resource.
+
** *PERMISSIVE*
+
Requests are allowed even when no policy is associated with a given resource.
+
** *DISABLED*
+
Completely disables the evaluation of policies and allows access to any resource. When `enforcement-mode` is `DISABLED`,
applications are still able to obtain all permissions granted by {project_name} through the <<_enforcer_authorization_context, Authorization Context>>
+
* *on-deny-redirect-to*
+
Defines a URL where a client request is redirected when an "access denied" message is obtained from the server. By default, the adapter responds with a 403 HTTP status code.
+
* *path-cache*
+
Defines how the policy enforcer should track associations between paths in your application and resources defined in {project_name}. The cache is needed to avoid
unnecessary requests to a {project_name} server by caching associations between paths and protected resources.
+
** *lifespan*
+
Defines the time in milliseconds when the entry should be expired. If not provided, default value is *30000*. A value equal to 0 can be set to completely disable the cache. A value equal to -1 can be set to disable the expiry of the cache.
+
** *max-entries*
+
Defines the limit of entries that should be kept in the cache. If not provided, default value is *1000*.
+
* *paths*
+
Specifies the paths to protect. This configuration is optional. If not defined, the policy enforcer discovers all paths by fetching the resources you defined to your application in {project_name}, where these resources are defined with `URIS` representing some paths in your application.
+
** *name*
+
The name of a resource on the server that is to be associated with a given path. When used in conjunction with a *path*, the policy enforcer ignores the resource's *URIS* property and uses the path you provided instead.
** *path*
+
(required) A URI relative to the application's context path. If this option is specified, the policy enforcer queries the server for a resource with a *URI* with the same value.
Currently a very basic logic for path matching is supported. Examples of valid paths are:
+
*** Wildcards: `/*`
*** Suffix: `/*.html`
*** Sub-paths: `/path/*`
*** Path parameters: /resource/{id}
*** Exact match: /resource
*** Patterns: /{version}/resource, /api/{version}/resource, /api/{version}/resource/*
+
** *methods*
+
The HTTP methods (for example, GET, POST, PATCH) to protect and how they are associated with the scopes for a given resource in the server.
+
*** *method*
+
The name of the HTTP method.
+
*** *scopes*
+
An array of strings with the scopes associated with the method. When you associate scopes with a specific method, the client trying to access a protected resource (or path) must provide an RPT that grants permission to all scopes specified in the list. For example, if you define a method _POST_ with a scope _create_, the RPT must contain a permission granting access to the _create_ scope when performing a POST to the path.
+
*** *scopes-enforcement-mode*
+
A string referencing the enforcement mode for the scopes associated with a method. Values can be *ALL* or *ANY*. If *ALL*,
all defined scopes must be granted in order to access the resource using that method. If *ANY*, at least one scope should be
granted in order to gain access to the resource using that method. By default, enforcement mode is set to *ALL*.
+
** *enforcement-mode*
+
Specifies how policies are enforced.
+
*** *ENFORCING*
+
(default mode) Requests are denied by default even when there is no policy associated with a given resource.
+
*** *DISABLED*
+
** *claim-information-point*
+
Defines a set of one or more claims that must be resolved and pushed to the {project_name} server in order to make these claims available to policies. See <<_enforcer_claim_information_point, Claim Information Point>> for more details.
+
* *lazy-load-paths*
+
Specifies how the adapter should fetch the server for resources associated with paths in your application. If *true*, the policy
enforcer is going to fetch resources on-demand accordingly with the path being requested. This configuration is specially useful
when you do not want to fetch all resources from the server during deployment (in case you have provided no `paths`) or in case
you have defined only a sub set of `paths` and want to fetch others on-demand.
+
* *http-method-as-scope*
+
Specifies how scopes should be mapped to HTTP methods. If set to *true*, the policy enforcer will use the HTTP method from the current request to
check whether or not access should be granted. When enabled, make sure your resources in {project_name} are associated with scopes representing each HTTP method you are protecting.
+
* *claim-information-point*
+
Defines a set of one or more *global* claims that must be resolved and pushed to the {project_name} server in order to make these claims available to policies. See <<_enforcer_claim_information_point, Claim Information Point>> for more details.

View file

@ -1,18 +0,0 @@
[[_enforcer_filter_using_https]]
= Configuring TLS/HTTPS
When the server is using HTTPS, ensure your policy enforcer is configured as follows:
[source,json]
----
{
"truststore": "path_to_your_trust_store",
"truststore-password": "trust_store_password"
}
----
The configuration above enables TLS/HTTPS to the Authorization Client, making possible to access a
{project_name} Server remotely using the HTTPS scheme.
[NOTE]
It is strongly recommended that you enable TLS/HTTPS when accessing the {project_name} Server endpoints.

View file

@ -1,5 +1,5 @@
[[_enforcer_js_adapter]]
= JavaScript integration
= JavaScript integration for Policy Enforcer
The {project_name} Server comes with a JavaScript library you can use to interact with a resource server protected by a policy enforcer.
This library is based on the {project_name} JavaScript adapter, which can be integrated to allow your client to obtain permissions from a {project_name} Server.

View file

@ -1,29 +0,0 @@
[[_enforcer_overview]]
= Policy enforcers
Policy Enforcement Point (PEP) is a design pattern and as such you can implement it in different ways. {project_name} provides all the necessary means
to implement PEPs for different platforms, environments, and programming languages. {project_name} Authorization Services presents a RESTful API,
and leverages OAuth2 authorization capabilities for fine-grained authorization using a centralized authorization server.
image:images/pep-pattern-diagram.png[alt="PEP overview"]
A PEP is responsible for enforcing access decisions from the {project_name} server where these decisions are taken by evaluating the policies
associated with a protected resource. It acts as a filter or interceptor in your application in order to check whether or not a particular request
to a protected resource can be fulfilled based on the permissions granted by these decisions.
{project_name} provides built-in support for enabling the *{project_name} Policy Enforcer* to Java applications with built-in support to secure JakartaEE-compliant frameworks and web containers.
If you are using Maven, you should configure the following dependency to your project:
```xml
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-policy-enforcer</artifactId>
<version>${keycloak.version}</version>
</dependency>
```
When you enable the policy enforcer all requests sent to your application are intercepted and access to protected resources will be granted
depending on the permissions granted by {project_name} to the identity making the request.
Policy enforcement is strongly linked to your application's paths and the <<_resource_overview, resources>> you created for a resource server using the {project_name} Administration Console. By default,
when you create a resource server, {project_name} creates a <<_resource_server_default_config, default configuration>> for your resource server so you can enable policy enforcement quickly.

View file

@ -16,7 +16,7 @@ image:images/resource-server/default-resource.png[alt="Default resource"]
This resource defines a `Type`, namely `urn:my-resource-server:resources:default` and a `URI` `/*`. Here, the `URI` field defines a
wildcard pattern that indicates to {project_name} that this resource represents all the paths in your application. In other words,
when enabling <<_enforcer_overview, policy enforcement>> for your application, all the permissions associated with the resource
when enabling policy enforcement for your application, all the permissions associated with the resource
will be examined before granting access.
The `Type` mentioned previously defines a value that can be used to create <<_permission_typed_resource, typed resource permissions>> that must be applied

View file

@ -1,158 +0,0 @@
[[_service_client_api]]
= Authorization client java API
Depending on your requirements, a resource server should be able to manage resources remotely or even check for permissions programmatically.
If you are using Java, you can access the {project_name} Authorization Services using the Authorization Client API.
It is targeted for resource servers that want to access the different endpoints provided by the server such as the Token Endpoint, Resource, and Permission management endpoints.
== Maven dependency
```xml
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-client</artifactId>
<version>${KEYCLOAK_VERSION}</version>
</dependency>
</dependencies>
```
== Configuration
The client configuration is defined in a ``keycloak.json`` file as follows:
[source,json,subs="attributes+"]
----
{
"realm": "hello-world-authz",
"auth-server-url" : "http://localhost:8080{kc_base_path}",
"resource" : "hello-world-authz-service",
"credentials": {
"secret": "secret"
}
}
----
* *realm* (required)
+
The name of the realm.
* *auth-server-url* (required)
+
The base URL of the {project_name} server. All other {project_name} pages and REST service endpoints are derived from this. It is usually in the form https://host:port{kc_base_path}.
* *resource* (required)
+
The client-id of the application. Each application has a client-id that is used to identify the application.
* *credentials* (required)
+
Specifies the credentials of the application. This is an object notation where the key is the credential type and the value is the value of the credential type.
The configuration file is usually located in your application's classpath, the default location from where the client is going to try to find a ```keycloak.json``` file.
== Creating the authorization client
Considering you have a ```keycloak.json``` file in your classpath, you can create a new ```AuthzClient``` instance as follows:
```java
// create a new instance based on the configuration defined in a keycloak.json located in your classpath
AuthzClient authzClient = AuthzClient.create();
```
== Obtaining user entitlements
Here is an example illustrating how to obtain user entitlements:
```java
// create a new instance based on the configuration defined in keycloak.json
AuthzClient authzClient = AuthzClient.create();
// create an authorization request
AuthorizationRequest request = new AuthorizationRequest();
// send the entitlement request to the server in order to
// obtain an RPT with all permissions granted to the user
AuthorizationResponse response = authzClient.authorization("alice", "alice").authorize(request);
String rpt = response.getToken();
System.out.println("You got an RPT: " + rpt);
// now you can use the RPT to access protected resources on the resource server
```
Here is an example illustrating how to obtain user entitlements for a set of one or more resources:
```java
// create a new instance based on the configuration defined in keycloak.json
AuthzClient authzClient = AuthzClient.create();
// create an authorization request
AuthorizationRequest request = new AuthorizationRequest();
// add permissions to the request based on the resources and scopes you want to check access
request.addPermission("Default Resource");
// send the entitlement request to the server in order to
// obtain an RPT with permissions for a single resource
AuthorizationResponse response = authzClient.authorization("alice", "alice").authorize(request);
String rpt = response.getToken();
System.out.println("You got an RPT: " + rpt);
// now you can use the RPT to access protected resources on the resource server
```
== Creating a resource using the protection API
```java
// create a new instance based on the configuration defined in keycloak.json
AuthzClient authzClient = AuthzClient.create();
// create a new resource representation with the information we want
ResourceRepresentation newResource = new ResourceRepresentation();
newResource.setName("New Resource");
newResource.setType("urn:hello-world-authz:resources:example");
newResource.addScope(new ScopeRepresentation("urn:hello-world-authz:scopes:view"));
ProtectedResource resourceClient = authzClient.protection().resource();
ResourceRepresentation existingResource = resourceClient.findByName(newResource.getName());
if (existingResource != null) {
resourceClient.delete(existingResource.getId());
}
// create the resource on the server
ResourceRepresentation response = resourceClient.create(newResource);
String resourceId = response.getId();
// query the resource using its newly generated id
ResourceRepresentation resource = resourceClient.findById(resourceId);
System.out.println(resource);
```
== Introspecting an RPT
```java
// create a new instance based on the configuration defined in keycloak.json
AuthzClient authzClient = AuthzClient.create();
// send the authorization request to the server in order to
// obtain an RPT with all permissions granted to the user
AuthorizationResponse response = authzClient.authorization("alice", "alice").authorize();
String rpt = response.getToken();
// introspect the token
TokenIntrospectionResponse requestingPartyToken = authzClient.protection().introspectRequestingPartyToken(rpt);
System.out.println("Token status is: " + requestingPartyToken.getActive());
System.out.println("Permissions granted by the server: ");
for (Permission granted : requestingPartyToken.getPermissions()) {
System.out.println(granted);
}
```

View file

@ -12,7 +12,7 @@ A <<_overview_terminology_permission_ticket, permission ticket>> is a special se
`A correlation handle that is conveyed from an authorization server to a resource server, from a resource server to a client, and ultimately from a client back to an authorization server, to enable the authorization server to assess the correct policies to apply to a request for authorization data.`
In most cases, you won't need to deal with this endpoint directly. {project_name} provides a <<_enforcer_overview, policy enforcer>> that enables UMA for your
In most cases, you won't need to deal with this endpoint directly. {project_name} provides a policy enforcer that enables UMA for your
resource server so it can obtain a permission ticket from the authorization server, return this ticket to client application, and enforce authorization decisions based on a final requesting party token (RPT).
The process of obtaining permission tickets from {project_name} is performed by resource servers and not regular client applications,

View file

@ -5,7 +5,7 @@ The Protection API provides a UMA-compliant set of endpoints providing:
* *Resource Management*
+
With this endpoint, resource servers can manage their resources remotely and enable <<_enforcer_overview, policy enforcers>> to query the server for the resources that need protection.
With this endpoint, resource servers can manage their resources remotely and enable policy enforcers to query the server for the resources that need protection.
* *Permission Management*
+

View file

@ -6,7 +6,7 @@ Sometimes you might want to introspect a requesting party token (RPT) to check i
There are two main use cases where token introspection can help you:
* When client applications need to query the token validity to obtain a new one with the same or additional permissions
* When enforcing authorization decisions at the resource server side, especially when none of the built-in <<_enforcer_overview, policy enforcers>> fits your application
* When enforcing authorization decisions at the resource server side, especially when none of the built-in policy enforcers fits your application
= Obtaining Information about an RPT
@ -83,4 +83,3 @@ This is essentially what the policy enforcers do. Be sure to:
[role="_additional-resources"]
.Additional resources
* https://datatracker.ietf.org/doc/html/rfc7519[JSON web token (JWT)]
* <<_enforcer_overview, policy enforcers>>

View file

@ -67,33 +67,6 @@ curl \
"http://localhost:8080{kc_realms_path}/master/protocol/openid-connect/token"
----
ifeval::[{project_community}==true]
=== Example using Java
There's a Java client library for the Admin REST API that makes it easy to use from Java. To use it from your application add a dependency on the
`keycloak-admin-client` library.
The following example shows how to use the Java client library to get the details of the master realm:
[source,java,subs="attributes+"]
----
import org.keycloak.admin.client.Keycloak;
import org.keycloak.representations.idm.RealmRepresentation;
...
Keycloak keycloak = Keycloak.getInstance(
"http://localhost:8080{kc_base_path}",
"master",
"admin",
"password",
"admin-cli");
RealmRepresentation realm = keycloak.realm("master").toRepresentation();
----
Complete Javadoc for the admin client is available at {apidocs_link}[{apidocs_name}].
endif::[]
=== Additional resources
[role="_additional-resources"]
* {adminguide_link}[{adminguide_name}]

View file

@ -696,7 +696,6 @@ Changes to {project_name} Authorization JavaScript adapter::
the same behavior as before. The main change is on how you invoke both `authorization` and `entitlement` methods which now
expect a specific object type representing an authorization request. This new object type provides more flexibility on how
permissions can be obtained from the server by supporting the different parameters supported by the UMA grant type.
See link:{authorizationguide_link}#_enforcer_js_adapter[{authorizationguide_name}] for details.
One of the main changes introduced by this release is that you are no longer required to exchange access tokens with RPTs in
order to access resources protected by a resource server (when not using UMA). Depending on how the policy enforcer is configured on the resource server side, you can just send regular