Passing End User Attributes to the Backend¶
There can be scenarios where a backend service needs to make different decisions or respond with different data, depending on the application end-user that consumes an API. To achieve this the backend service needs to have access to the respective end-user's data at the time an API call takes place.
This can be facilitated by the Gateway by sending the end user attributes that are defined in the respective user store, in a JWT via an HTTP header, to the backend service when the API call is being forwarded.
How does it work?¶
The backend JSON Web Token (JWT) contains the claims that are transferred between two parties, such as the end-user and the backend. A claim is an attribute of the user that is mapped to the underlying user store. A set of claims is referred to as a dialect (e.g., http://wso2.org/claims).
If you enable backend JWT generation in the Gateway, each API request will carry a digitally signed JWT, which is in the following format to the backend service.
{token header}.{claims list}.{signature}
When the request goes through the Gateway, the backend JWT is appended as a transport header to the outgoing message. The backend service fetches the JWT and retrieves the required information about the user, application, or token.
Sample backend JWT¶
The following is an example of a backend JWT:
{
"typ": "JWT",
"alg": "RS256",
"x5t": "ODE3Y2ZhMTBjMDM4ZTBmMjAyYzliYTI2YjRhYTZlOGIyZmUxNWE3YQ==",
"kid": "Q049bG9jYWxob3N0LCBPVT1XU08yLCBPPVdTTzIsIEw9TW91bnRhaW4gVmlldywgU1Q9Q0EsIEM9VVMjMTY3NzA4OTI4Mw"
}
{
"iss":"wso2.org/products/am",
"exp":1345183492181,
"http://wso2.org/claims/subscriber":"admin",
"http://wso2.org/claims/applicationname":"app2",
"http://wso2.org/claims/apicontext":"/placeFinder",
"http://wso2.org/claims/version":"1.0.0",
"http://wso2.org/claims/tier":"Silver",
"http://wso2.org/claims/enduser":"sumedha"
}
The above JSON Web Token (JWT) contains the following information.
JWT Header :
"typ"
- Declares that the encoded object is a JWT access token"alg"
- This defines the specific algorithm intended for use with the key"x5t"
- Thumbprint of the x.509 cert (SHA-1 thumbprint)"kid"
- Key ID parameter is a unique identifier used to match a specific key
JWT Claims set :
"iss"
- The issuer of the JWT"exp"
- The token expiration time"http://wso2.org/claims/subscriber"
- Subscriber to the API, usually the app developer" http://wso2.org/claims/applicationname"
- Application through which API invocation is done" http://wso2.org/claims/apicontext"
- Context of the API" http://wso2.org/claims/version "
- API version" http://wso2.org/claims/tier"
- Tier/price band for the subscription" http://wso2.org/claims/enduser"
- End-user of the app who's action invoked the AP
Enabling the default backend JWT generator¶
Before passing end user attributes, you need to enable and configure the JWT implementation, as mentioned below in Choreo Connect.
-
Open the Choreo Connect configuration file according to the deployment type you are using.
Click here to see the configuration file location for your Choreo Connect deployment.
Navigate to the correct folder path and open the
config.toml
orconfig-toml-configmap.yaml
file based on your Choreo Connect deployment.Deployment Mode File name Directory Docker Compose Choreo Connect as a Standalone Gateway config.toml
<CHOREO-CONNECT_HOME>/docker-compose/choreo-connect/conf/
Docker Compose Choreo Connect with MWARE ESB as a Control Plane config.toml
<CHOREO-CONNECT_HOME>/docker-compose/choreo-connect-with-apim/conf/
Kubernetes Choreo Connect as a Standalone Gateway config-toml-configmap.yaml
<CHOREO-CONNECT_HOME>/k8s-artifacts/choreo-connect/
Kubernetes Choreo Connect with MWARE ESB as a Control Plane config-toml-configmap.yaml
<CHOREO-CONNECT_HOME>/k8s-artifacts/choreo-connect-with-apim/
-
Enable and configure the backend JWT implementation.
The following is the basic configuration that you need to have in place to enable backend JWT. For more information, on the other backend JWT configurations, see JWT generation configuration details.
[enforcer.jwtGenerator] enabled = true
-
Start the server.
For more information, see the Quick Start Guide.
Enabling a customized backend JWT generator¶
Note
MWARE ESB comes with the default JWT generator. This JWT generator will generate specific claims based on the specifications and the user demands at the time the product is released. When you update the products, you will need to add/change some of the claims based on the specification updates. This means that even with the given released version, standard claims that come from the ESB are subjected to change. Therefore, if you have planned to use specific claims in the backend, it is always recommended to implement a custom JWT generator with mandatory claims you wish to consume at your backend
When generating the backend JWT, it retrieves the claims from the invoked JWT. If you need to change the way that JWT is generated in Choreo Connect, such as by adding additional claims or by completely changing the JWT, follow the instructions below to implement the customized Gateway JWT generation:
-
Write your own JWTGenerator class extending the
org.wso2.carbon.apimgt.common.gateway.jwtgenerator.AbstractAPIMgtGatewayJWTGenerator
class.Info
Choreo Connect uses the AbstractAPIMgtGatewayJWTGenerator class to support JWT generation within Choreo Connect.
package org.wso2.carbon.test; import org.osgi.service.component.annotations.Component; import org.wso2.carbon.apimgt.common.gateway.dto.JWTInfoDto; import org.wso2.carbon.apimgt.common.gateway.jwtgenerator.APIMgtGatewayJWTGeneratorImpl; import org.wso2.carbon.apimgt.common.gateway.jwtgenerator.AbstractAPIMgtGatewayJWTGenerator; import java.util.Map; import java.util.UUID; @Component( enabled = true, service = AbstractAPIMgtGatewayJWTGenerator.class, name = "customgatewayJWTGenerator" ) public class CustomGatewayJWTGenerator extends APIMgtGatewayJWTGeneratorImpl { @Override public Map<String, Object> populateStandardClaims(JWTInfoDto jwtInfoDto) { return super.populateStandardClaims(jwtInfoDto); } @Override public Map<String, Object> populateCustomClaims(JWTInfoDto jwtInfoDto) { Map<String, Object> claims = super.populateCustomClaims(jwtInfoDto); claims.put("uuid", UUID.randomUUID().toString()); return claims; } }
Click here for a sample Custom Gateway JWTGenerator.
-
Build your class and add the JAR file in the
<CHOREO-CONNECT_HOME>/resources/enforcer/dropins
directory.Note
If you use Choreo Connect with Helm Charts, please refer to the documentation in here to add a JAR file into the dropins directory.
-
Enable and configure the JWT implementation.
-
For more information, see JWT generation configuration details.
-
Set
enforcer.jwtGenerator.gatewayGeneratorImpl
to your customized class name.[enforcer.jwtGenerator] gatewayGeneratorImpl = "org.wso2.carbon.test.CustomGatewayJWTGenerator"
-
-
Start the server.
For more information, see the Quick Start Guide.
Backend JWT generator configuration details¶
The following is a sample configuration.
[enforcer.jwtGenerator]
enabled = true
encoding = "base64" # base64,base64url
claimDialect = "http://wso2.org/claims"
convertDialect = false
header = "X-JWT-Assertion"
signingAlgorithm = "SHA256withRSA"
enableUserClaims = false
gatewayGeneratorImpl = "org.wso2.carbon.test.CustomGatewayJWTGenerator"
claimsExtractorImpl = "org.wso2.carbon.apimgt.impl.token.ExtendedDefaultClaimsRetriever"
publicCertificatePath = "/home/wso2/security/truststore/mg.pem"
privateKeyPath = "/home/wso2/security/keystore/mg.key"
The relevant elements in the JWT generation configuration are described below. If you do not configure these elements, they take their default values.
Element | Description | Default Value |
---|---|---|
|
Uncomment this property and set this value to true to enable JWT. |
false |
|
The name of the HTTP header to which the JWT is attached. | X-JWT-Assertion |
|
The JWT access token contains all claims that are defined in the |
http://wso2.org/claims |
|
Remap the OIDC claims into the configured dialect. | false |
|
The signing algorithm is used to sign the JWT. The general format of the JWT is This element can have only two values - the default values are |
SHA256withRSA |
|
Enable/disable user claims in the token. |
false |
|
Fully qualified custom JWT generator to used in JWT(Self Contained) Access Tokens. |
org.wso2.carbon.apimgt.common.gateway.jwtgenerator.APIMgtGatewayJWTGeneratorImpl |
|
Fully qualified custom Claim Retriever to add custom claims into JWT. |
org.wso2.carbon.apimgt.impl.token.ExtendedDefaultClaimsRetriever |
|
How many requests to the JWKS endpoint can be served in the time window. |
1000 |
|
Time window for the rate limit to reset. |
false |
|
How many requests to the JWKS endpoint can be served in the time window |
1000 |
|
An object containing the paths to public certificate and private key of an RSA keypair and specifying whether to use it for signing or not. |
{
privateKeyPath = "/home/wso2/security/keystore/mg.key"
publicCertificatePath = "/home/wso2/security/truststore/mg.pem"
useForSigning = true
} |
|
Path of the public certificate |
/home/wso2/security/truststore/mg.pem |
|
Path of the private key |
/home/wso2/security/keystore/mg.key |
|
Whether to use key for signing. |
false |
JWKS endpoint for backend JWTs¶
Backend JWTs can be signed with RSA to ensure their validity when being sent between 2 parties. To verify the JWT on the backend we need the public certificate of the private key used to sign the JWT at the Gateway. The JWKS endpoint is a way to get this public certificate.
Usage¶
The JWKS endpoint is:
"https://<hostname>:<port>/.wellknown/jwks"
"https://localhost:9095/.wellknown/jwks"
The public keys can be received from this endpoint with a GET
or POST
request.
Sample JWKS response¶
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"kid": "ZjcwNmI2ZDJmNWQ0M2I5YzZiYzJmyNg",
"alg": "RS256",
"n": "8vjeHzRhvpfMystncPnLBWy_t5F3eCxbcLbdugWnzfnIgaV6TWnqPBUagJBKpzRZs4A9Qja_ZrSVJjYsbARzCS_qiWp0Cdwkqn6ZCXpmbpfjYnKORq8N8M-zWaSZYbNvWJ5oSO4kH-LKWzODaFebwTJBpsR1vChHH95doxFuUjiZaisVaQgUJ6drRdlDtImp9r9EAX36YROuYFPouD-dQ1sdJOa11P_yMs-glfQ"
}
]
}
JWKS Parameters¶
Parameter | Description |
---|---|
|
Key type identifies the cryptographic family this key belongs to. |
|
The exponent value of the public key. |
|
This defines the use of the key, whether it is used for signing or encryption. |
|
This is an ID parameter used to match a specific key(s). |
|
This defines the specific algorithm intended for use with the key. |
|
The modulus value of the public key. |
|
An array of the public keys available from the gateway. |
Code Example in Ballerina¶
import ballerina/http;
import ballerina/jwt;
service / on new http:Listener(8080) {
resource function get hello(http:Request request) returns string|error {
// JWT Validator config configured with the Issuer and the Signature config which points at the JWKS URL
jwt:ValidatorConfig validatorConfig = {
issuer: "wso2.org/products/am",
clockSkew: 60,
signatureConfig: {
jwksConfig: {url: "https://gateway.e1-us-east-azure.preview-dv.choreoapis.dev/.wellknown/jwks", cacheConfig: {}}
}
};
var jwt = request.getHeader("x-jwt-assertion");
if !(jwt is string) {
return error("JWT header not available");
}
// Validating the JWT based on its signature and expiration time
jwt:Payload|jwt:Error result = check jwt:validate(jwt, validatorConfig);
if result is jwt:Error {
return error("Failed to authenticate " + result.message());
}
return result.toBalString();
}
}
In this example we create a hello route on port 8080 and secure it with JWT. This hello function returns the JWT claims or the error that occurred during validation.
See Also¶
If you want to learn how you can pass end user attributes to the backend when working with the default API Gateway, see Passing Enduser Attributes to the Backend, which is under the API Gateway documentation section.
Top