A Duct library that provides Integrant keys and associated code implementing a :duct.middleware.buddy/authentication compatible JWT token validation function for OpenID Connect ID Tokens.
See OpenID Connect Core 1.0 Terminology for additional details on the meaning of the OpenID Connect terms used below.
To use this library you also need to add the following dependency to your project (use the most recent version of it):
[duct/middleware.buddy "0.2.0"]
The library caches both the OpenID Provider signing keys and a configurable amount of ID Token validation results, to speed up repeated token validation. The signing keys are cached for a configurable amount of time (see below). The ID Token validation results are cached until ID Token expiration time in case the token is successfully validated, or for an hour if it is not valid.
The library only supports asymmetric signatures for ID Tokens, and marks any ID Token signed with a symmetric signature as invalid (regardless of its actual validity!). The rationale for this decision is that regarding symmetric signatures OpenID Connect Core 1.0 specification states that.:
"Symmetric signatures MUST NOT be used by public (non-confidential) Clients because of their inability to keep secrets."
Web applications are non-confidential by their very nature, so the library refuses to validate symmetric signatures.
The library currently supports a single Integrant key:
:dev.gethop.buddy-auth/jwt-oidc
. To initialize it, the following keys
are mandatory and their values must not be nil
:
:claims
key which is a map with the set of OpenID Connect claims
that the ID Token should satisfy. At least the following mandatory
keys should be specified:
:iss
is the URL, using the https scheme with no query or
fragment component, that the ID Token OpenID Provider (OP)
asserts as its Issuer Identifier. This also must be identical to
the iss
Claim value in ID Tokens issued by this OP.:aud
are the audience(s) that ID Tokens issued by the
<issuer-identifier-url>
are intended for. It contains the
OAuth 2.0 client_id
of the Relying Party as an audience
value. It may also contain identifiers for other audiences. In
the general case, the <aud-values>
value is an array of
case-sensitive strings. In the common special case when there is
just one audience, the aud value MAY be a single case-sensitive
string.:well-known-url
is the URL of the OpenID Provider's
Configuration Document (also known as the "well-known
openid-configuration"). It must be a string
or a
java.net.URL
value.:jwks-uri
is the URL of the OpenID Provider's JSON Web Key Set
[JWK] document. This contains the signing key(s) the Relaying
Party uses to validate signatures from the OpenID Provider. It
must be a string
or a java.net.URL
value.You can also use the following optional configuration keys:
:pubkeys-expire-in
which is the time to live for the cached OpenID
Provider signing keys. It has to be specified in an integral number
of seconds greater than zero. If not specified the default value is
86400 (one day).:max-cached-tokens
which is the maximum amount of cached ID Token
validation results. It has to be an integer value greater than
zero. If not specified, the default value is 50.:well-known-retrieval-timeout
which specifies the connection
timeout (in milli-seconds) for "well-known openid-configuration"
retrieval. It has to be an integer value greater than zero. If not
specified, the default value is 500 milli-seconds.:well-known-retrieval-retries
which specifies the number of
additional retries in case of connection failure for "well-known
openid-configuration" retrieval. It has to be an integer value
greater than zero. If not specified, the default value is 3 retries.:jwks-retrieval-timeout
which specifies the connection timeout (in
milli-seconds) for JWKS retrieval. It has to be an integer value
greater than zero. If not specified, the default value is 500
milli-seconds.:jwks-retrieval-retries
which specifies the number of additional
retries in case of connection failure for JWKS retrieval. It has to
be an integer value greater than zero. If not specified, the default
value is 3 retries.:logger
a value that implements the duct.logger/Logger
protocol. If not nil
, the library will log any relevant issues
that may prevent tokens from being validated (e.g., inability to get
the JWKS URL, getting invalid keys in the JWKS document, etc.)Examples (using all optional configuration keys with their default values):
{:dev.gethop.buddy-auth/jwt-oidc
{:claims {:iss #duct/env ["ISSUER_URL" Str]
:aud #duct/env ["AUDIENCE" Str]}
:well-known-url #duct/env ["WELL_KNOWN_URL" Str]
:pubkeys-expire-in 86400
:max-cached-tokens 50
:well-known-retrieval-timeout 500
:well-known-retrieval-retries 3
:logger #ig/ref :duct/logger}}
{:dev.gethop.buddy-auth/jwt-oidc
{:claims {:iss #duct/env ["ISSUER_URL" Str]
:aud #duct/env ["AUDIENCE" Str]}
:jwks-uri #duct/env ["JWKS_URI" Str]
:pubkeys-expire-in 86400
:max-cached-tokens 50
:jwks-retrieval-timeout 500
:jwks-retrieval-retries 3
:logger #ig/ref :duct/logger}}
Initializing the key returns an authfn
function that can be used in
conjunction with
:duct.middleware.buddy/authentication.
Example:
{:dev.gethop.buddy-auth/jwt-oidc
{:claims {:iss #duct/env ["ISSUER_URL" Str]
:aud #duct/env ["AUDIENCE" Str]}
:jwks-uri #duct/env ["JWKS_URI" Str]
:logger #ig/ref :duct/logger}
:duct.middleware.buddy/authentication
{:backend :token
:token-name "Bearer"
:authfn #ig/ref :dev.gethop.buddy-auth/jwt-oidc}}
The authfn
function does all the OpenID Connect ID Token validation
process
and returns the value of the sub
claim if the ID Token was
successfully validated. Otherwise, it returns nil
. The function
throws AssertionError
if any of the following conditions occur:
:jwks-uri
is not a string
or a valid java.net.URL
value.:iss
is nil
:aud
is nil
The library includes self-contained units tests, and an integration
test that depends on AWS Cognito User Pools. That test is named
dev.gethop.buddy-auth.jwt-oidc-test.test-cognito-token-validation
and
has the ^:integration
metadata keyword associated to it, so you can
exclude it from your unit tests runs.
If you want to run the integration test, the following set of environment variables are needed (the first three are the standard AWS credentials environment variables):
AWS_ACCESS_KEY_ID
: The Access key ID of an AWS IAM user. That user
must have permission to perform the InitiateAuth
action, on the AWS
cognito-idp
resource that points to a particular AWS Cognito User
Pool.AWS_SECRET_ACCESS_KEY
: The Secret Access key associated to the
previous Access key ID.AWS_DEFAULT_REGION
: The region where the User Pool is located at.COGNITO_TESTS_USER_POOL_CLIENT_ID
: The ID of an "App client" that
is allowed to interact with the User Pool.COGNITO_TESTS_ISSUER_URL
: The Issuer URL (iss
claim, in OpenID
Connect terminology) used by the User Pool when minting OpenID
Connect ID Tokens. See ID Token Payload
for additional details.COGNITO_TESTS_AUDIENCE
: This is the Audience (aud
, in OpenID
Connect terminology), that contains the User Pool client_id
used
for the user authenticated. See the previous link for additional
details.COGNITO_TESTS_JWKS_URI
: The URI of the JSON Web Key Set (JWKS)
for the User Pool. See step 2.a in Step 2: Validate the JWT
Signature
for additional details.COGNITO_TESTS_USERNAME
: The "sign in" value of an existing user in
the User Pool (note that depending on the User Pool configuration,
the "sign in" value can be a username, an email address, or other
values).COGNITO_TESTS_PASSWORD
: The password for the previous user name.COGNITO_TESTS_SUB
: The subject value (sub
claim, in OpenID
Connect terminology) assigned to the previous user in the User Pool.Copyright (c) 2023 Magnet S. Coop
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/
Can you improve this documentation? These fine people already did:
Iñaki Arenaza, spietras, lucassousaf & Bingen Galartza IparragirreEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close