Configure JWT authentication
JWT authentication is a generic, secure method for applications running on various platforms to authenticate to Conjur using a unique identity token or a third-party machine identity signed by a JWT provider.
You must have Conjur admin permissions to perform this task. |
Before you begin
-
This section assumes your application uses a JWT for authentication, and that the JWT is signed. For details, see JSON Web Token (JWT).
-
Make sure the time on the Conjur machine and the JWT provider time are synced. You can use the secured NTP service to synchronize the times.
-
Important! Make sure you fully understand the Important guidelines for configuring JWT authentication.
There are many ways to define the JWT authentication. The example JWT authentication configured is just one configuration example.
-
The example in this sections use the following information:
-
Authentication is based on the
token-app-property
variable. -
App ID path: host/jwt-apps
-
JWT Provider: https://vendorHost.example.com
-
Example JWT:
{ "ver": "2.0", "iss": "https://login.example.com", "sub": "AAAAAAAAAAAAAAAIkzqFVrSaSaFHy782bbtaQ", "aud": ["service1","service2","conjur"], "exp": 1537361411, "iat": 1537274711, "nbf": 1537274711, "workspace": "production_emp", "app_name": "myapp", "app_id": "app530", "additional_data": { "group_name": "mygroup", "group_id": "group21", "team_name": "myteam", "team_id": "team76", }, "client_id": "s6BhgRkqt3", "state": "af0ifjslrkj" "oid": "00000000-0000-0000-66f3-3332eca7ea91", "tid": "9122040d-6c67-4c5b-b112-36a304b66dad", "nonce": "123456", "aio": "Df2UXL1ix!lv8q5!eGbIDaky5mnOreY" }
-
-
Decide which claims in the JWT you want to use to set up the JWT authentication.
Based on the example JWT above, let's use the
workspace
,app_name
, andadditional_data/group_id
claims to define the authentication:{ "ver": "2.0", "iss": "https://login.example.com", "sub": "AAAAAAAAAAAAAAAIkzqFVrSaSaFHy782bbtaQ", "aud": ["service1","service2","conjur"], "exp": 1537361411, "iat": 1537274711, "nbf": 1537274711, "workspace": "production_emp", "app_name": "myapp", "app_id": "app530", "additional_data": { "group_name": "mygroup", "group_id": "group21", "team_name": "myteam", "team_id": "team76", }, "client_id": "s6BhgRkqt3", "state": "af0ifjslrkj" "oid": "00000000-0000-0000-66f3-3332eca7ea91", "tid": "9122040d-6c67-4c5b-b112-36a304b66dad", "nonce": "123456", "aio": "Df2UXL1ix!lv8q5!eGbIDaky5mnOreY" }
Configure the JWT authentication
This section describes how to set up a JWT Authenticator in Conjur so that your application can use a JWT to authenticate to Conjur.
Step 1: Configure JWT authentication
-
Define a JWT Authenticator
Create a Conjur policy for the JWT Authenticator.
-
Save the following policy as authn-jwt.yml:
- !policy id: conjur/authn-jwt/<SERVICE_ID> body: - !webservice # Mandatory variable: How the JWT Authenticator gets the signing keys # Uncomment either 'jwks-uri' or 'public-keys #- !variable jwks-uri #- !variable public-keys # Optional variables # Uncomment one or all of the following optional variables # Note: If you uncomment 'identity-path' you must also uncomment 'token-app-property' # Note: If you uncomment 'public-keys' above you must also uncomment 'issuer' #- !variable ca-cert #- !variable token-app-property #- !variable identity-path #- !variable issuer #- !variable enforced-claims #- !variable mapping-claims #- !variable audience # Group of applications that can authenticate using this JWT Authenticator - !group apps - !permit role: !group apps privilege: [ read, authenticate ] resource: !webservice - !webservice status # Group of users who can check the status of the JWT Authenticator - !group operators - !permit role: !group operators privilege: [ read ] resource: !webservice status
-
Replace <SERVICE_ID> with a name that helps identify the authenticator, for example,
prod
,dev
,myVendor
, and so on. For information about service IDs, see Authenticator service IDs. -
Select the policy variables:
Use the following diagram as a guide:
-
Uncomment one of provider signing key variables, depending on how the JWT Authenticator will receive the JWT signing key:
Signing key provider
Description
jwks-uri
The resource for a set of JSON-encoded public keys, one of which corresponds to the key used to digitally sign the JWT. The keys must be encoded as a JWK Set (RFC7517).
Value: A JWKS URI, beginning with
https://
JWKS URI examples:
-
Google -
https://www.googleapis.com/oauth2/v3/certs
-
Microsoft -
https://login.microsoftonline.com/common/discovery/v2.0/keys
-
GitLab -
https://gitlab.com/-/jwks
When Conjur is unable to reach a remote JWKS URI endpoint, you can use this variable to provide a static JWKS to the JWT Authenticator.
When using this variable, it is assumed that the JWT includes an
iss
claim, and you must also define theissuer
variable (see optional variables below).Value: A JSON object (jwks.json) containing two fields:
type
andvalue
, wheretype
is always set tojwks
(string value), andvalue
is set to the JWKS value defined by the JWT provider.{ "type": "jwks", "value": <JWKS VALUE AS DEFINED BY THE IDENTITY PROVIDER> }
-
-
Uncomment the optional variables by which Conjur should create a relationship with the app ID.
These are optional yet recommended. For more information, see Configure JWT authentication.
Click to see the variable descriptionsVariable
Description
ca-cert
When the JWKS provider server uses a self-signed certificate or the certificate is signed by third-party CA, use this variable to establish a TLS connection and validate server identity.
Certificates from this variable (can be one or many certificates) override default operating system CA certificate bundles when fetching the JWKS from the remote URI.
Value: The X.509 public key certificate or certificate bundle. Each certificate in the bundle should be in PEM (RFC7468) format.
Required: No
Use
token-app-property
to create a 1:1 mapping between the JWT Authenticator and the authenticating application.You populate
token-app-property
with the name of a claim in the JWT, for example"app-id"
.When you define an app ID for the authenticating application, its
host id
must match the JWT claim's value.For example, say the JWT has the following claim:
"app-id": "app530"
-
You populate the
token-app-property
withapp-id
-
You define the app ID as follows:
- !host app530
.
The JWT Authenticator uses this mapping to validate the identity of the authenticating application.
-
You can populate this variable with one claim only.
For nested claims, specify the path to the nested claim:
<claim_root>/<claim_name>
-
Claims names that contain a slash (/) or a colon (:) are not supported.
Required: No, but highly recommended
identity-path
Further to defining the
token-app-property
variable, you can use theidentity-path
variable to define the app ID's path in Conjur, thereby completing the full app ID name.The JWT Authenticator narrows validation of the authenticating application by the app ID, and in the defined identity path.
identity-path
has no purpose when standing alone. It should be used only iftoken-app-property
is defined.Required: No
JWT Authenticator validates the issuer of the JWT.
The
issuer
variable value must be identical to theiss
claim value.Required:
-
When signing keys are static, that is, when the
public-keys
variable (see signing key provider variables) is defined in the policy, this variable is required
-
When the sign keys come from the JWKS URI, this variable is optional. In this case, if you do not define this variable, the issuer is taken from the jwks-uri.
enforced-claims
You can define a list of enforced claims in the JWT Authenticator.
All Conjur app IDs that work with the JWT Authenticator endpoint must include these enforced claims in their host annotations.
When this variable is defined in the JWT Authenticator, it must be populated with at least one claim. Separate multiple claims with commas:
custom_claim1,custom_claim2
.For nested claims, specify the path to the nested claim:
<claim_root>/<claim_name>
-
You cannot enforce reserved claims (
iss
,exp
,nbf
,iat
,aud
,jti
). -
When a claim is enforced, application identities that do not include this claim as a host annotation will no longer be able to authenticate to Conjur and must be deleted and redefined..
Required: No
Claim names in JWTs do not always represent their essence. For example
ref
might actually indicate a namespace ID, or a branch.You can map claim names to more user-friendly aliases in your app ID's host annotations, instead of the actual claim name.
Following on from the example above, you can map
ref
tonamespace
, and then usenamespace
in the host annotation. So the host annotation would look as follows:authn-jwt/<service-id>/namespace: theNamespace
Because of this mapping, the JWT Authenticator knows to check the JWT's
ref
value.When this variable is defined in the JWT Authenticator, it must be populated with at least one mapping statement, in the following format:
<target-annotation-name>:<source-claim-name>
For nested claims, specify the path to the nested source claim:
<target-annotation-name>:<source_claim_root>/<source_claim_name>
Separate multiple mapping statements with commas:
<target-annotation-name_1>:<source-claim-name_1>,<target-annotation-name_2>:<source-claim-name_2>
-
You cannot map reserved claims to aliases (
iss
,exp
,nbf
,iat
,aud
,jti
). -
Application identities (
hosts
) that were defined prior to mapping the claim to an alias, and whose host annotations include the mapped claim, must be redefined to use alias.
Required: No
audience
If the JWT has an audience claim (
aud
), you can include this variable to authenticate theaud
claim. Theaudience
variable accepts a single value and must match theaud
claim value.If the
aud
claim contains an array, the array must include theaudience
variable value.Required: No
Example policy usingtoken-app-property
The following policy defines a JWT Authenticator,
auth-jwt/myVendor
that uses the following variables:-
token-app-property
andidentity-path
to create a 1:1 relationship between the application and Conjur -
enforced-claims
to enforce usingadditional_data/group_id
as one of the app ID's host annotations -
jwks-uri
for the JWKS signing keys URI
The Authenticator Status (
status
) webservice defined in the policy verifies the status of the JWT Authenticator. It identifies whether or not the JWT Authenticator configuration was successful. Make sure to grant permissions to the user groups that should be able to check JWT Authenticator status by adding them to the operators group. For details on defining groups in policy, see Group.- !policy id: conjur/authn-jwt/myVendor body: - !webservice # Mandatory variable: How the JWT Authenticator gets the signing keys # Uncomment either 'jwks-uri' or 'public-keys - !variable jwks-uri #- !variable public-keys # Optional variables # Uncomment one or all of the following optional variables # Note: If you uncomment 'identity-path' you must also uncomment 'token-app-property' # Note: If you uncomment 'public-keys' above you must also uncomment 'issuer' #- !variable ca-cert - !variable token-app-property - !variable identity-path #- !variable issuer - !variable enforced-claims #- !variable mapping-claims #- !variable audience # Group of applications that can authenticate using this JWT Authenticator - !group apps - !permit role: !group apps privilege: [ read, authenticate ] resource: !webservice - !webservice status # Group of users who can check the status of the JWT Authenticator - !group operators - !permit role: !group operators privilege: [ read ] resource: !webservice status
-
-
-
Load the policy into root:
conjur policy load -f /path/to/file/authn-jwt.yml -b root
-
-
Populate the policy variables
In this step, populate the variables that you defined in the JWT Authenticator policy above:
-
Populate
jwks-uri
with the signing key URI,https://vendorHost.example.com/path/to/jwks
:conjur variable set -i conjur/authn-jwt/myVendor/jwks-uri -v https://vendorHost.example.com/path/to/jwks
-
Because we are using the
app_name
claim to create the 1:1 relationship, populatetoken-app-property
as follows (you can populate this variable with one claim only):conjur variable set -i conjur/authn-jwt/myVendor/token-app-property -v app_name
-
Populate
identity-path
with the app ID path, (without thehost/
prefix):conjur variable set -i conjur/authn-jwt/myVendor/identity-path -v jwt-apps
-
Populate
enforced-claims
with theadditional_data/group_id
:conjur variable set -i conjur/authn-jwt/myVendor/enforced-claims -v additional_data/group_id
-
-
Define an app ID (
host
)In this step, you define an identity in Conjur for your applications. This app ID is represented as a
host
in Conjur.Save the following policy as authn-jwt-hosts.yml:
- !policy id: <policy-id> body: - !group - &hosts - !host id: <host-id> annotations: authn-jwt/<SERVICE_ID>/<claim>: <claim value> #authn-jwt/<SERVICE_ID>/<claim>: <claim value> - !grant role: !group members: *hosts - !grant role: !group conjur/authn-jwt/<SERVICE_ID>/apps member: !group <policy-id>
-
If you defined the
token-app-property
in the JWT Authenticator configuration, use the best practices when defining the host. -
Define at least one annotation.
The more annotations you define, the tighter the application security. You can define any string-type claim from the JWT as an annotation, for example,
workspace
andadditional_data/group_id
. Note that theadditional_data/group_id
annotation is mandatory becauseadditional_data/group_id
is an enforced claim in the JWT Authenticator policy.-
Nested claims are supported.
-
Arrays are currently not supported.
-
- !policy id: jwt-apps body: - !group - &hosts - !host id: myapp annotations: authn-jwt/myVendor/workspace: production_emp authn-jwt/myVendor/additional_data/group_id: group21 - !grant role: !group members: *hosts - !grant role: !group conjur/authn-jwt/myVendor/apps member: !group jwt-apps
Load the policy into any policy level, for example, to load into root:
conjur policy load -f /path/to/file/authn-jwt-hosts.yml -b root
-
Step 2: Check the authenticator status
Check that the JWT Authenticator is configured correctly. For details, see Authenticator Status Webservice.
Step 3: Allowlist the JWT Authenticator
In this step, you add the JWT Authenticator to the list of allowed authenticators in Conjur.
You need to enable the authenticator on every Follower you want to authenticate to. For details, see Configure authenticators.
Send a JWT authentication request
Use the following URI to send a JWT authentication request to Conjur:
|
For example, using the following details:
Parameter |
Example |
---|---|
Conjur-server-hostname |
myorg.example.com |
service-id |
myVendor |
account |
cucumber |
host-id |
Following the example JWT authentication we configured above, which uses the |
the resulting request looks as follows:
|
For more details about sending authentication requests, see the JWT Authenticator REST API.
Modify JWT Authenticator
When you make certain modifications to a JWT Authenticator endpoint, app IDs in Conjur that use the modified endpoint must be adjusted accordingly. This section describes these JWT Authenticator modifications and the required app ID policy adjustments.
App owners must be notified of these modifications so that they can adjust their app IDs accordingly. App IDs that are not adjusted will not be able to authenticate to Conjur due to mismatched configurations. |
Claim alias mapping
If you modify the claim-aliases
variable definition in the JWT Authenticator, application identities that include this claim mapping in their annotations must be modified accordingly.
Take, for example, the JWT Authenticator defined above in Configure JWT authentication.
Say you add the claim-aliases
variable to the JWT Authenticator policy, and populate it as follows:
|
In the myapp
app ID (see Define an app ID (host)), the authn-jwt/myVendor/workspace: production_emp
annotation must be adjusted accordingly to authn-jwt/myVendor/environment: production_emp
:
|
Enforced claims
If you add or modify the enforced-claims
variable definition in the JWT Authenticator, application identities that do not include this enforced claim in its annotations must be modified to include it.
Take, for example, the JWT Authenticator defined above in Configure JWT authentication.
Say you want to enforce the team_id
claim in the JWT Authenticator policy. Modify (repopulate) the enforced-claims
variable as follows:
|
The app ID (see Define an app ID (host)) must now include annotations for both the additional_data/group_id
and team_id
claims:
|
Troubleshooting
Resolution; Verify that only one of the following conditions apply:
-
Preferred - more secure: The
token-app-property
variable is configured in the JWT Authenticator policy and populated with the field name where to fetch the JWT identity, and thehost-id
URL is not included in the REST API call. -
The
host-id
URL is included in the REST API call. This option should not be used in production.
Possible cause: The jwks-url
is not configured as a variable in the JWT Authenticator policy.
Resolution: Ensure that the jwks-uri
variables is configured in the JWT Authenticator policy and that the variable has been populated with appropriate URL.
Possible cause: The hostname in the jwks-uri
variable does not match the iss
claim in the JWT.
Resolution:
-
Decode the JWT and verify the value of the
iss
claim. -
Configure the
issuer
variable in the JWT Authenticator policy.- !variable id: issuer
-
Populate the
issuer
variable with the same value as in theiss
claim.conjur variable set -i conjur/authn-jwt/myVendor/issuer -v example.com
Problem: Couldn't find the public key with the specified key ID (kid) in the signed token.
Resolution: Check that the JWT provider that signed the JWT is aligned with the jwks-uri
in the JWT Authenticator policy configuration:
-
Open the logs and look for message CONJ00072I.
For example:
CONJ00072I Fetching JWKS from 'https://dev-842018.oktapreview.com/oauth2/v1/keys'...
-
Go to the URL in the message, and search for the key ID (
kid
) values.In the following example, there are two keys with
kid
values:{"keys":[{"kty":"RSA","alg":"RS256","kid":"Hwy-KfNZ9XVPspytNALP9oZn9WuD3WQNut-yychEqzw","use":"sig","e":"AQAB","n":"nXPdUWijFy-KUxeA8Esc4qYTeBVJPP6cXOFUtOggqa_waSbG7xAuF-pBT8vLDn5t1xXDTVfwMdGz_88pjTNDxF8zZjElmvg13oQLi8sIQ6QvFv38gAbY0rRvcMVDsUdUoMhMlCzFtei-XKSkQDsswx07C7zLBiVF3dxLuPytJK4TYNOUXkL4EevDu7Gri-TN_r32oTWMKp9UOV0aUa72T2DEHjH2_piF1kTnOm8sCUSbUIuT1J-X-hRpX91kyiV4TvsK3QwTy9MrTPuPgf_5VMVfvE_fuZUiR7VtyPUWS6eyrwTa38__883LsbCg_-z0PxDoDFZnPp45gslZIGlwpw"},{"kty":"RSA","alg":"RS256","kid":"qyZVEfsbkqOJttJQ4Eg2SwolCAAIRgXl4IoKAOZC5Yg","use":"sig","e":"AQAB","n":"jLbzvq5MVJl7MwauCm-T3H8OEgm4Geoa5hZ0X2OmorYZTz6IN73Hb_a0EKADMW6-usytVK98hDHfZnuvoB12IqKsUMF07ViOgHLq-e3hAqDCd3N_wsJDke64Aodb9YGclz8NtBhu95UHbKBgSB-iBXs2YC18rrYzQm65DA46tsQVAJpb5uMdMQay6r-kc7WKX3vZKl65EC-gn2n0fXJ0w2jVNM0PJwsnB2o_60oLOk_lg5li4a02cX2LHRSKOsm98pUHRTUiYBJcvI1sT_8CB264jEYYMKiwi3EX5yMdEWHwmAfIAfLxW-nZcjb0oM6sQFcshR9mKeYJi0vy8gsksw"}]}
-
Verify that either one of the
kid
keys is in the JWT header:For example, if you decode the following encoded token:
eyJraWQiOiJ5VWVSV2pNT3B2UllUZWdvVTBzUGhCWlZ4QUdPclFzbmc5a29oYk53MkhZIiwiYWxnIjoiUlMyNTYifQ.eyJ2ZXIiOjEsImp0aSI6IkFULnpRNjc1V1B0TnQyZjV0b0wxWmx4UTFLQjVVVml6QmpvUjVRX05GNnBlZ1UiLCJpc3MiOiJodHRwczovL2Rldi04NDIwMTgub2t0YXByZXZpZXcuY29tIiwiYXVkIjoiaHR0cHM6Ly9kZXYtODQyMDE4Lm9rdGFwcmV2aWV3LmNvbSIsInN1YiI6Im5lc3NpQGN5YmVyYXJrLmNvbSIsImlhdCI6MTYyMjk3NzI3MCwiZXhwIjoxNjIyOTgwODcwLCJjaWQiOiIwb2F6M3c5MjNwYlhrSG1sTDBoNyIsInVpZCI6IjAwdWtzeHozbzJ2RkpDWDIzMGg3Iiwic2NwIjpbIm9wZW5pZCJdfQ.VvLXNvSpJy08ldl1JPxosH0a1uZsxPMEEhVK60aQJWR7e0cGQlyaFd2zrJkUdHwJpXO5IXhDlyfuFVASNHwsf-SDakqOaW3T97GPpDV3JonOB_D5EiHbKw2TIEedbrERauDQNA2ddbrqFQ8SHUP_4pbYZ0765GMdr89YNCNgAQd2sj20VAclVBF-k6pAshlA_aGTTNuG3HaLDDNsl2moIskUXFpfoKWbnRvgjRoYP58ReWvXIjO_5TpT_NAiedseeZvLFjgamTremKISq3GJWM-QGHT0c60D2-NMmoVG4UgKZQPl63huMEU7xIl-Uha0MVa38F2Nnh9AxuuW1Q0DoQ
you'll get:
{ "kid": "yUeRWjMOpvRYTegoU0sPhBZVxAGOrQsng9kohbNw2HY", "alg": "RS256" }
If you cannot verify that the kid is in the header, contact CyberArk Customer Support for further assistance.
Problem: JWT authentication is failing.
Possible cause: The JWT Authenticator configuration was modified and the associated app ID was not updated accordingly, so they are mismatched.
Solution: Check with your Conjur admin whether modifications were made to the endpoint. If so, adjust your app ID accordingly. For details, see Modify JWT Authenticator.
Problem: JWT authentication is failing.
Possible cause: Claims names and claim aliases must not contain a slash (/) or a colon (:).
Solution: Make sure the claim alias complies with the acceptable format. See Claim alias mapping.
Problem: JWT authentication is failing.
Possible cause:token-app-property
is in the incorrect format.
Solution: Make sure token-app-property
complies with the acceptable format. See token-app-property.
Problem: JWT authentication is failing.
Possible cause: The claim value contains an array - arrays are not supported.
Solution: Use a claim that does not contain an array.
Problem: JWT authentication is failing.
Possible cause: The nested claim might not include the full path.
Solution:In the host annotation, make sure that the nested claim includes its full path: <claim_root>/<claim_name>
.