FIDO2 WebAuthn (Passkey) Multifactor Authentication

WebAuthn is an API that makes it very easy for a relying party, such as a web service, to integrate strong authentication into applications using support built in to all leading browsers and platforms. This means that web services can now easily offer their users strong authentication with a choice of authenticators such as security keys or built-in platform authenticators such as biometric readers.

:warning: Usage Warning!

To use WebAuthn support in a cluster, you must either enable session affinity (so that the same user always connects to the same node), or replicate the web session across all nodes in the cluster.

Support is enabled by including the following module in the WAR overlay:

1
2
3
4
5
<dependency>
    <groupId>org.apereo.cas</groupId>
    <artifactId>cas-server-support-webauthn</artifactId>
    <version>${cas.version}</version>
</dependency>
1
implementation "org.apereo.cas:cas-server-support-webauthn:${project.'cas.version'}"
1
2
3
4
5
6
7
8
9
dependencyManagement {
    imports {
        mavenBom "org.apereo.cas:cas-server-support-bom:${project.'cas.version'}"
    }
}

dependencies {
    implementation "org.apereo.cas:cas-server-support-webauthn"
}
1
2
3
4
5
6
7
8
9
10
dependencies {
    /*
        The following platform references are included automatically and are listed for reference only.

        implementation enforcedPlatform("org.apereo.cas:cas-server-support-bom:${project.'cas.version'}")
        implementation platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)
        
    */
    implementation "org.apereo.cas:cas-server-support-webauthn"
}
:information_source: WebAuthn vs Passkeys

WebAuthn (Web Authentication) is a W3C specification and browser API that enables web applications to register and authenticate users using public-key cryptography in a phishing-resistant way. Passkeys are a specific type of WebAuthn credential designed to replace passwords by using asymmetric key pairs. During registration, an authenticator on the user’s device generates a private-public key pair; the public key is sent to the service, and the private key remains securely on the device (or synced via a cloud backup). In summary, WebAuthn is the underlying protocol/API that supports multiple authentication methods (hardware keys, platform authenticators, etc.), whereas passkeys are a user-facing credential format specifically built on WebAuthn for passwordless login.

The following settings and properties are available from the CAS configuration catalog:

cas.authn.mfa.web-authn.core.application-idThe extension input to set for the appid extension when initiating authentication operations.
no default
Required

The extension input to set for the appid extension when initiating authentication operations. If this member is set, starting an assertion op will automatically set the appid extension input, and finish assertion op will adjust its verification logic to also accept this AppID as an alternative to the RP ID. By default, this is not set.

Type
String
Default
none
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.relying-party-idThe id that will be set as the rp parameter when initiating registration operations, and which id hash will be compared against.
no default
Required

The id that will be set as the rp parameter when initiating registration operations, and which id hash will be compared against. This is a required parameter. A successful registration or authentication operation requires rp id hash to exactly equal the SHA-256 hash of this id member. Alternatively, it may instead equal the SHA-256 hash of application id if the latter is present.

Type
String
Default
none
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.relying-party-nameThe human-palatable name of the Relaying Party.
no default
Required

The human-palatable name of the Relaying Party.

Type
String
Default
none
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.crypto.encryption.keyThe encryption key is a string whose length is defined by the encryption key size setting.
no default
RequiredSpEL

The encryption key is a string whose length is defined by the encryption key size setting.

Type
String
Default
none
Defined by
EncryptionJwtCryptoProperties
Supports
Spring Expression Language
cas.authn.mfa.web-authn.crypto.signing.keyThe signing key is a string whose length is defined by the signing key size setting.
no default
RequiredSpEL

The signing key is a string whose length is defined by the signing key size setting.

Type
String
Default
none
Defined by
SigningJwtCryptoProperties
Supports
Spring Expression Language
cas.authn.mfa.web-authn.core.allow-primary-authenticationConfigure the authentication flow to allow web-authn to be used as the first primary factor for authentication.
false

Configure the authentication flow to allow web-authn to be used as the first primary factor for authentication. Registered accounts with a valid webauthn registration record can choose to login using their device as the first step.

Type
Boolean
Default
false
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.allow-untrusted-attestationIf false finish registration op will only allow registrations where the attestation signature can be linked to a trusted attestation root.
false

If false finish registration op will only allow registrations where the attestation signature can be linked to a trusted attestation root. This excludes self attestation and none attestation. Regardless of the value of this option, invalid attestation statements of supported formats will always be rejected. For example, a "packed" attestation statement with an invalid signature will be rejected even if this option is set to true.

Type
Boolean
Default
false
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.allowed-originsThe allowed origins that returned authenticator responses will be compared against.
no default

The allowed origins that returned authenticator responses will be compared against. The default is set to the server name. A successful registration or authentication operation requires origins to exactly equal one of these values.

Type
String
Default
none
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.attestation-conveyance-preferenceAccepted values are: DIRECT , INDIRECT , NONE .
DIRECT

Accepted values are: DIRECT, INDIRECT, NONE. The argument for the attestation parameter in registration operations. Unless your application has a concrete policy for authenticator attestation, it is recommended to leave this parameter undefined.

Type
String
Default
DIRECT
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.authenticator-attachmentSpecifies the desired authenticator attachment modality during credential registration.
no default

Specifies the desired authenticator attachment modality during credential registration.

This is used by the WebAuthn client/browser to select which type of authenticator may be used to create the credential.

  • PLATFORM: an authenticator built into, or tightly bound to, the user's device, such as Touch ID, Windows Hello, Android/iOS passkeys.
  • CROSS_PLATFORM: an external/roaming authenticator usable across multiple devices, such as a USB, NFC, or BLE security key like a YubiKey.

If unset, the client may use any available authenticator.

Type
String
Default
none
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.display-name-attributeName of the principal attribute that indicates the principal's display name, primarily used for device registration.
displayName

Name of the principal attribute that indicates the principal's display name, primarily used for device registration.

Type
String
Default
displayName
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.enabledWhether WebAuthn functionality should be activated and enabled.
true

Whether WebAuthn functionality should be activated and enabled.

Type
Boolean
Default
true
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.expire-devicesExpire and forget device registration records after this period.
30

Expire and forget device registration records after this period.

Type
Long
Default
30
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.expire-devices-time-unitDevice registration record expiration time unit.
days

Device registration record expiration time unit.

Type
TimeUnit
Default
days
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.hintsUser-agent hints, in descending order of preference, sent with registration and authentication requests to guide the browser towards the kind of authenticator to offer first.
no default

User-agent hints, in descending order of preference, sent with registration and authentication requests to guide the browser towards the kind of authenticator to offer first.

Hints do not restrict which authenticator may be used, and where they conflict with the authenticator attachment, browsers that support them follow the hints.

  • security-key: a physical security key, such as a USB or NFC key.
  • client-device: an authenticator on the device in use, such as the platform passkey manager.
  • hybrid: a phone or other general-purpose device, usually reached by scanning a QR code.

If unset, no hints are sent.

Type
List<String>
Default
none
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.multiple-device-registration-enabledWhen enabled, allows the user/system to accept multiple accounts and device registrations per user, allowing one to switch between or register new devices/accounts automatically.
false

When enabled, allows the user/system to accept multiple accounts and device registrations per user, allowing one to switch between or register new devices/accounts automatically.

Type
Boolean
Default
false
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.passkey-enroll-urlURL of the page where a user creates a passkey for the account, published as enroll in the passkey endpoints document at /.well-known/passkey-endpoints , so that password managers can send users straight to it.
no default

URL of the page where a user creates a passkey for the account, published as enroll in the passkey endpoints document at /.well-known/passkey-endpoints, so that password managers can send users straight to it. If unset and account management is enabled, the multifactor devices panel of the account profile is used; otherwise no enrollment page is published.

Type
String
Default
none
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.passkey-manage-urlURL of the page where a user manages the account's passkeys, published as manage in the passkey endpoints document at /.well-known/passkey-endpoints .
no default

URL of the page where a user manages the account's passkeys, published as manage in the passkey endpoints document at /.well-known/passkey-endpoints. If unset and account management is enabled, the multifactor devices panel of the account profile is used; otherwise no management page is published.

Type
String
Default
none
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.passkey-upgrade-enabledOffer a passkey right after a password login: CAS shows a short page that asks the browser's password manager to create a passkey for the account on its own (WebAuthn conditional create), then continues as usual.
false

Offer a passkey right after a password login: CAS shows a short page that asks the browser's password manager to create a passkey for the account on its own (WebAuthn conditional create), then continues as usual. Browsers and password managers that do not support it continue immediately.

Takes effect only when allow-primary-authentication and allow-untrusted-attestation are also enabled, since such passkeys come without attestation and are meant for passkey login; otherwise this setting is ignored.

Type
Boolean
Default
false
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.qr-code-authentication-enabledWhen enabled, allows the user to a scan a QR code on an external device and authenticate later on the primary device.
false

When enabled, allows the user to a scan a QR code on an external device and authenticate later on the primary device. This is useful in scenarios where the primary authentication device is not registered with CAS and the user has a secondary device that is registered and does not wish to use the primary device to authenticate for security or other practical reasons.

Type
Boolean
Default
false
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.trusted-device-enabledIndicates whether this provider should support trusted devices.
false

Indicates whether this provider should support trusted devices.

Type
Boolean
Default
false
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.user-verification-requirementSpecifies the relying party's requirement for user verification during credential registration and/or authentication.
no default

Specifies the relying party's requirement for user verification during credential registration and/or authentication.

User verification means the authenticator verifies the user locally, for example with a PIN, fingerprint, face recognition, or device unlock. This is stronger than simple user presence, such as touching a security key.

  • REQUIRED: user verification must be performed; the operation should fail if it is unavailable or not completed.
  • PREFERRED: user verification should be performed if possible, but the operation may still succeed without it.
  • DISCOURAGED: user verification is not requested, typically to reduce friction or avoid prompting for PIN/biometric verification.

The server should validate the resulting authenticator data flags according to the configured requirement.

Type
String
Default
none
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.core.validate-signature-counterIf true, finish assertion op will fail if the signature counter value in the response is not strictly greater than the stored signature counter value.
true

If true, finish assertion op will fail if the signature counter value in the response is not strictly greater than the stored signature counter value.

Type
Boolean
Default
true
Defined by
WebAuthnMultifactorAuthenticationCoreProperties
cas.authn.mfa.web-authn.crypto.algThe signing/encryption algorithm to use.
no default

The signing/encryption algorithm to use.

Type
String
Default
none
Defined by
EncryptionJwtSigningJwtCryptographyProperties
cas.authn.mfa.web-authn.crypto.enabledWhether crypto operations are enabled.
true

Whether crypto operations are enabled.

Type
Boolean
Default
true
Defined by
EncryptionJwtSigningJwtCryptographyProperties
cas.authn.mfa.web-authn.crypto.encryption.key-sizeThe encryption key size.
512

The encryption key size.

Type
Integer
Default
512
Defined by
EncryptionJwtCryptoProperties
cas.authn.mfa.web-authn.crypto.signing.key-sizeThe signing key size.
512

The signing key size.

Type
Integer
Default
512
Defined by
SigningJwtCryptoProperties
cas.authn.mfa.web-authn.crypto.strategy-typeControl the cipher sequence of operations.
ENCRYPT_AND_SIGN
Control the cipher sequence of operations. The accepted values are:
  • ENCRYPT_AND_SIGN: Encrypt the value first, and then sign.
  • SIGN_AND_ENCRYPT: Sign the value first, and then encrypt.
Type
String
Default
ENCRYPT_AND_SIGN
Defined by
EncryptionJwtSigningJwtCryptographyProperties

Required settings may be needed to activate or affect the feature; review them even when they have a default. Optional settings only need to be set to change a default or to turn on the behavior they control. Third party settings belong to libraries such as Spring Boot that CAS builds on; their own documentation may have more detail.

Signing & encryption

This CAS feature is able to accept signing and encryption crypto keys. In most scenarios if keys are not provided, CAS will auto-generate them. The following instructions apply if you wish to manually and beforehand create the signing and encryption keys.

Note that if you are asked to create a JWK of a certain size for the key, you are to use the following set of commands to generate the token:

1
2
wget https://raw.githubusercontent.com/apereo/cas/master/etc/jwk-gen.jar
java -jar jwk-gen.jar -t oct -s [size]

The outcome would be similar to:

1
2
3
4
5
{
  "kty": "oct",
  "kid": "...",
  "k": "..."
}

The generated value for k needs to be assigned to the relevant CAS settings. Note that keys generated via the above algorithm are processed by CAS using the Advanced Encryption Standard (AES) algorithm which is a specification for the encryption of electronic data established by the U.S. National Institute of Standards and Technology.


Notes on configuration

Configuration Metadata

The collection of configuration properties listed in this section are automatically generated from the CAS source and components that contain the actual field definitions, types, descriptions, modules, etc. This metadata may not always be 100% accurate, or could be lacking details and sufficient explanations.

Be Selective

This section is meant as a guide only. Do NOT copy/paste the entire collection of settings into your CAS configuration; rather pick only the properties that you need. Do NOT enable settings unless you are certain of their purpose and do NOT copy settings into your configuration only to keep them as reference. All these ideas lead to upgrade headaches, maintenance nightmares and premature aging.

YAGNI

Note that for nearly ALL use cases, declaring and configuring properties listed here is sufficient. You should NOT have to explicitly massage a CAS XML/Java/etc configuration file to design an authentication handler, create attribute release policies, etc. CAS at runtime will auto-configure all required changes for you. If you are unsure about the meaning of a given CAS setting, do NOT turn it on without hesitation. Review the codebase or better yet, ask questions to clarify the intended behavior.

Naming Convention

Property names can be specified in very relaxed terms. For instance cas.someProperty, cas.some-property, cas.some_property are all valid names. While all forms are accepted by CAS, there are certain components (in CAS and other frameworks used) whose activation at runtime is conditional on a property value, where this property is required to have been specified in CAS configuration using kebab case. This is both true for properties that are owned by CAS as well as those that might be presented to the system via an external library or framework such as Spring Boot, etc.

:information_source: Note

When possible, properties should be stored in lower-case kebab format, such as cas.property-name=value. The only possible exception to this rule is when naming actuator endpoints; The name of the actuator endpoints (i.e. ssoSessions) MUST remain in camelCase mode.

Settings and properties that are controlled by the CAS platform directly always begin with the prefix cas. All other settings are controlled and provided to CAS via other underlying frameworks and may have their own schemas and syntax. BE CAREFUL with the distinction. Unrecognized properties are rejected by CAS and/or frameworks upon which CAS depends. This means if you somehow misspell a property definition or fail to adhere to the dot-notation syntax and such, your setting is entirely refused by CAS and likely the feature it controls will never be activated in the way you intend.

Validation

Configuration properties are automatically validated on CAS startup to report issues with configuration binding, especially if defined CAS settings cannot be recognized or validated by the configuration schema. Additional validation processes are also handled via Configuration Metadata and property migrations applied automatically on startup by Spring Boot and family.

Indexed Settings

CAS settings able to accept multiple values are typically documented with an index, such as cas.some.setting[0]=value. The index [0] is meant to be incremented by the adopter to allow for distinct multiple configuration blocks.

Bypass

The following settings and properties are available from the CAS configuration catalog:

cas.authn.mfa.web-authn.bypass.groovy.locationThe location of the resource.
no default
Required

The location of the resource. Resources can be URLs, or files found either on the classpath or outside somewhere in the file system.

In the event the configured resource is a Groovy script, especially if the script is set to reload on changes, you may need to adjust the total number of inotify instances. On Linux, you may need to add the following line to /etc/sysctl.conf: fs.inotify.max_user_instances = 256.

You can check the current value via cat /proc/sys/fs/inotify/max_user_instances.

In situations and scenarios where CAS is able to automatically watch the underlying resource for changes and detect updates and modifications dynamically, you may be able to specify the following setting as either an environment variable or system property with a value of false to disable the resource watcher: org.apereo.cas.util.io.PathWatcherService.

Type
Resource
Default
none
Defined by
GroovyMultifactorAuthenticationProviderBypassProperties
cas.authn.mfa.web-authn.bypass.rest.urlThe endpoint URL to contact and retrieve attributes.
no default
RequiredSpEL

The endpoint URL to contact and retrieve attributes.

Type
String
Default
none
Defined by
RestfulMultifactorAuthenticationProviderBypassProperties
Supports
Spring Expression Language
cas.authn.mfa.web-authn.bypass.authentication-attribute-nameSkip multifactor authentication based on designated authentication attribute names.
no default

Skip multifactor authentication based on designated authentication attribute names.

Type
String
Default
none
Defined by
MultifactorAuthenticationProviderBypassProperties
cas.authn.mfa.web-authn.bypass.authentication-attribute-valueOptionally, skip multifactor authentication based on designated authentication attribute values.
no default
Regex

Optionally, skip multifactor authentication based on designated authentication attribute values. Multiple values may be separated by a comma.

Type
String
Default
none
Defined by
MultifactorAuthenticationProviderBypassProperties
cas.authn.mfa.web-authn.bypass.authentication-handler-nameSkip multifactor authentication depending on form of primary authentication execution.
no default
Regex

Skip multifactor authentication depending on form of primary authentication execution. Specifically, skip multifactor if the a particular authentication handler noted by its name successfully is able to authenticate credentials in the primary factor. Multiple values may be separated by a comma.

Type
String
Default
none
Defined by
MultifactorAuthenticationProviderBypassProperties
cas.authn.mfa.web-authn.bypass.authentication-method-nameSkip multifactor authentication depending on method/form of primary authentication execution.
no default
Regex

Skip multifactor authentication depending on method/form of primary authentication execution. Specifically, skip multifactor if the authentication method attribute collected as part of authentication metadata matches a certain value. Multiple values may be separated by a comma.

Type
String
Default
none
Defined by
MultifactorAuthenticationProviderBypassProperties
cas.authn.mfa.web-authn.bypass.credential-class-typeSkip multifactor authentication depending on form of primary credentials.
no default

Skip multifactor authentication depending on form of primary credentials. Value must equal the fully qualified class name of the credential type.

Type
String
Default
none
Defined by
MultifactorAuthenticationProviderBypassProperties
cas.authn.mfa.web-authn.bypass.http-request-headersSkip multifactor authentication if the http request contains the defined header names.
no default
Regex

Skip multifactor authentication if the http request contains the defined header names. Header names may be comma-separated and can be regular expressions; values are ignored.

Type
String
Default
none
Defined by
MultifactorAuthenticationProviderBypassProperties
cas.authn.mfa.web-authn.bypass.http-request-remote-addressSkip multifactor authentication if the http request's remote address or host matches the value defined here.
no default
Regex

Skip multifactor authentication if the http request's remote address or host matches the value defined here. The value may be specified as a regular expression.

Type
String
Default
none
Defined by
MultifactorAuthenticationProviderBypassProperties
cas.authn.mfa.web-authn.bypass.principal-attribute-nameSkip multifactor authentication based on designated principal attribute names.
no default

Skip multifactor authentication based on designated principal attribute names.

Type
String
Default
none
Defined by
MultifactorAuthenticationProviderBypassProperties
cas.authn.mfa.web-authn.bypass.principal-attribute-valueOptionally, skip multifactor authentication based on designated principal attribute values.
no default
Regex

Optionally, skip multifactor authentication based on designated principal attribute values.

Type
String
Default
none
Defined by
MultifactorAuthenticationProviderBypassProperties
cas.authn.mfa.web-authn.bypass.rest.basic-auth-passwordIf REST endpoint is protected via basic authentication, specify the password for authentication.
no default

If REST endpoint is protected via basic authentication, specify the password for authentication.

Type
String
Default
none
Defined by
RestfulMultifactorAuthenticationProviderBypassProperties
cas.authn.mfa.web-authn.bypass.rest.basic-auth-usernameIf REST endpoint is protected via basic authentication, specify the username for authentication.
no default

If REST endpoint is protected via basic authentication, specify the username for authentication.

Type
String
Default
none
Defined by
RestfulMultifactorAuthenticationProviderBypassProperties
cas.authn.mfa.web-authn.bypass.rest.headersHeaders, defined as a Map, to include in the request when making the REST call.
no default

Headers, defined as a Map, to include in the request when making the REST call. Will overwrite any header that CAS is pre-defined to send and include in the request. Key in the map should be the header name and the value in the map should be the header value.

Type
Map<String,String>
Default
none
Defined by
RestfulMultifactorAuthenticationProviderBypassProperties
cas.authn.mfa.web-authn.bypass.rest.maximum-retry-attemptsWhen attempting to reach the endpoint, this setting controls the number of retry attempts that CAS should execute Setting this value to a zero or negative value will disable the retry policy.
3

When attempting to reach the endpoint, this setting controls the number of retry attempts that CAS should execute Setting this value to a zero or negative value will disable the retry policy.

Type
Integer
Default
3
Defined by
RestfulMultifactorAuthenticationProviderBypassProperties
cas.authn.mfa.web-authn.bypass.rest.methodHTTP method to use when contacting the rest endpoint.
GET

HTTP method to use when contacting the rest endpoint. Examples include GET, POST, etc.

Type
String
Default
GET
Defined by
RestfulMultifactorAuthenticationProviderBypassProperties

Required settings may be needed to activate or affect the feature; review them even when they have a default. Optional settings only need to be set to change a default or to turn on the behavior they control. Third party settings belong to libraries such as Spring Boot that CAS builds on; their own documentation may have more detail.

Groovy scripting

CAS takes advantage of Apache Groovy in forms of either embedded or external scripts that allow one to, by default, dynamically build constructs, attributes, access strategies and a lot more. To activate the functionality described here, you may need to prepare CAS to support and integrate with Apache Groovy.

Please review this guide to configure your build.

Notes on configuration

Configuration Metadata

The collection of configuration properties listed in this section are automatically generated from the CAS source and components that contain the actual field definitions, types, descriptions, modules, etc. This metadata may not always be 100% accurate, or could be lacking details and sufficient explanations.

Be Selective

This section is meant as a guide only. Do NOT copy/paste the entire collection of settings into your CAS configuration; rather pick only the properties that you need. Do NOT enable settings unless you are certain of their purpose and do NOT copy settings into your configuration only to keep them as reference. All these ideas lead to upgrade headaches, maintenance nightmares and premature aging.

YAGNI

Note that for nearly ALL use cases, declaring and configuring properties listed here is sufficient. You should NOT have to explicitly massage a CAS XML/Java/etc configuration file to design an authentication handler, create attribute release policies, etc. CAS at runtime will auto-configure all required changes for you. If you are unsure about the meaning of a given CAS setting, do NOT turn it on without hesitation. Review the codebase or better yet, ask questions to clarify the intended behavior.

Naming Convention

Property names can be specified in very relaxed terms. For instance cas.someProperty, cas.some-property, cas.some_property are all valid names. While all forms are accepted by CAS, there are certain components (in CAS and other frameworks used) whose activation at runtime is conditional on a property value, where this property is required to have been specified in CAS configuration using kebab case. This is both true for properties that are owned by CAS as well as those that might be presented to the system via an external library or framework such as Spring Boot, etc.

:information_source: Note

When possible, properties should be stored in lower-case kebab format, such as cas.property-name=value. The only possible exception to this rule is when naming actuator endpoints; The name of the actuator endpoints (i.e. ssoSessions) MUST remain in camelCase mode.

Settings and properties that are controlled by the CAS platform directly always begin with the prefix cas. All other settings are controlled and provided to CAS via other underlying frameworks and may have their own schemas and syntax. BE CAREFUL with the distinction. Unrecognized properties are rejected by CAS and/or frameworks upon which CAS depends. This means if you somehow misspell a property definition or fail to adhere to the dot-notation syntax and such, your setting is entirely refused by CAS and likely the feature it controls will never be activated in the way you intend.

Validation

Configuration properties are automatically validated on CAS startup to report issues with configuration binding, especially if defined CAS settings cannot be recognized or validated by the configuration schema. Additional validation processes are also handled via Configuration Metadata and property migrations applied automatically on startup by Spring Boot and family.

Indexed Settings

CAS settings able to accept multiple values are typically documented with an index, such as cas.some.setting[0]=value. The index [0] is meant to be incremented by the adopter to allow for distinct multiple configuration blocks.

Discoverable Credentials

It is possible to allow WebAuthN to act as a standalone authentication strategy for primary authentication. Using this approach, user accounts and FIDO2-enabled devices that have already registered with CAS are given the option to login using their FIDO2-enabled device for a passwordless authentication experience.

Discoverable Credential means that the private key and associated metadata is stored in persistent memory on the authenticator, instead of encrypted and stored on the relying party server.

Device registration can occur out of band using available CAS APIs, or by allowing users to pass through the registration flow as part of the typical multifactor authentication.

The same passkeys are also offered by passwordless authentication, from the autofill menu of its username field and from its selection menu.

A passkey is bound to the relying party identifier (cas.authn.mfa.web-authn.core.relying-party-id, or the host of the CAS server name). When CAS is reached from origins whose domain differs from that identifier, list them under cas.authn.mfa.web-authn.core.allowed-origins. CAS accepts assertions from those origins and publishes them for WebAuthn related origin requests at /.well-known/webauthn:

1
2
3
4
5
6
{
  "origins": [
    "https://sso.example.org",
    "https://login.example.co.uk"
  ]
}

Browsers fetch this document from https://<relying party identifier>/.well-known/webauthn, at the root of the host and outside the CAS context path, and they only honor a limited number of distinct registrable domains in it. When CAS runs under a context path such as /cas, route the document onto the path CAS serves, either in the proxy that fronts CAS or with the embedded Tomcat rewrite valve registered on the engine:

1
RewriteRule ^/\.well-known/webauthn$ /cas/.well-known/webauthn [L]

Passkey Endpoints

CAS publishes the passkey endpoints metadata at /.well-known/passkey-endpoints, which password managers and passkey providers read to send users to the pages where passkeys are created (enroll) and managed (manage):

1
2
3
4
{
  "enroll": "https://sso.example.org/cas/account",
  "manage": "https://sso.example.org/cas/account"
}

Each URL is taken from CAS settings. When one is not set and account management is enabled, it points to the account profile, where WebAuthn devices are listed and registered; otherwise it is left out, and an empty document still tells clients that CAS supports passkeys. Like the related origins document, clients fetch it from the root of the relying party identifier’s host, so route it onto the CAS context path the same way:

1
RewriteRule ^/\.well-known/passkey-endpoints$ /cas/.well-known/passkey-endpoints [L]

Signal API

After a successful WebAuthn authentication, CAS uses the WebAuthn Signal API, where the browser supports it, to report the passkeys it still accepts for the user and the user’s current name and display name. Password managers and platform authenticators can then stop offering passkeys that were removed from CAS and show the account as it is named in CAS. Browsers without the Signal API ignore this.

Passkey Provider Names

Each registration keeps the AAGUID that identifies the authenticator or passkey provider that created it. When the attestation does not name the device, which is the case for synced passkeys, the account profile shows the provider name, such as Google Password Manager, 1Password or Apple Passwords, from a bundled snapshot of the community passkey provider AAGUID list. The registration page shows the same name, with the provider’s icon from that list, right after a passkey is registered. Providers that send an all-zero AAGUID, and devices registered before CAS kept the AAGUID, stay unnamed.

Passkey Upgrades

CAS can offer a passkey to users who sign in with a username and password, without a separate enrollment step, using WebAuthn conditional create. Right after the password login, CAS shows a short intermediate page that asks the browser to create a passkey for the account. If the browser’s password manager has just filled in the password for that account, it may create the passkey on its own, usually with no prompt; otherwise the request fails silently. Either way the page continues to the application within a few seconds, and browsers that do not support conditional create continue immediately.

:information_source: Passkey Upgrades

Passkey upgrades must be explicitly enabled in CAS configuration. Then, note that this feature also only takes effect when WebAuthn is allowed for primary authentication and when untrusted attestation is allowed. Review CAS settings to ensure all features are correctly enabled.

The intermediate page is shown only when the login was completed with a password typed in that login, and the account may register another device: it has no device yet, or multiple registration is turned on. The passkey is named after the username that was typed, so that the password manager can match it with the saved password, and it belongs to the authenticated principal. It is listed with its provider’s name, such as Google Password Manager, or as Passkey.

Conditional create is supported by recent versions of Chrome with Google Password Manager and Safari with iCloud Keychain, and by many third-party password managers.