Repository: authelia/authelia (go)

Issue:
Segmentation violation
### Version


v4.38.16

### Deployment Method


Docker

### Reverse Proxy


Traefik

### Reverse Proxy Version


2.10.7

### Description


The docker container crashes on startup.

### Reproduction


Simply run the container with the config below and it will crash immediately.

### Expectations


_No response_

### Configuration (Authelia)


```yaml
---
###############################################################
#                   Authelia configuration                    #
###############################################################

# This secret can also be set using the env variables AUTHELIA_JWT_SECRET_FILE
# generate with 'docker run authelia/authelia:latest authelia crypto rand --length 128 --charset alphanumeric'

identity_validation:
  reset_password:
    jwt_secret: xxxx
default_redirection_url: https://auth.domain.com

log:
  level: debug

totp:
  issuer: auth.domain.com

# register to duo to use this
# duo_api:
#  hostname: api-123456789.example.com
#  integration_key: ABCDEF
#  # This secret can also be set using the env variables AUTHELIA_DUO_API_SECRET_KEY_FILE
#  secret_key: 1234567890abcdefghifjkl

authentication_backend:
  file:
    path: /config/users_database.yml

access_control:
  default_policy: deny
  rules:
    # Rules applied to everyone # bypass, one_factor, two_factor
    - domain: unsecure.whoami.example.com
      policy: bypass
    - domain: domain.com
      policy: one_factor
    - domain: "*.domain.com"
      policy: bypass

session:
  name: authelia_session
  secret: xxxx
  expiration: 1h
  inactivity: 5m
  remember_me: 1M
  cookies:
    - domain: domain.com
      authelia_url: https://auth.domain.com

regulation:
  max_retries: 3
  find_time: 120  # how often max retires are counted
  ban_time: 300

storage:
# generate with 'docker run authelia/authelia:latest authelia crypto rand --length 128 --charset alphanumeric'
  encryption_key: xxxx
  local:
    path: /config/db.sqlite3

notifier:
  smtp:
    username: xxxx
    # This secret can also be set using the env variables AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE
    password: xxx
    address: xxxx
    sender: xxx
  # For testing purpose, notifications can be sent in a file.
  # filesystem:
  #   filename: /config/notification.txt

identity_providers:
  oidc:
    ## The other portions of the mandatory OpenID Connect 1.0 configuration go here.
    ## See: https://www.authelia.com/c/oidc
    ##### generate with 'docker run authelia/authelia:latest authelia crypto rand --length 128 --charset alphanumeric'
    hmac_secret: xxxx
    # INFO: n and e values are not from an actual key
    jwks:
      - use: sig
        kty: RSA
        kid: default
        alg: RS256
        n: 234823498234982398472342387623498674726394823748234
        e: 65537
    clients:
    - client_id: portainer
      client_name: Portainer
      # generate with 'docker run authelia/authelia:latest authelia crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986'
      client_secret: 'xxxx'.
      public: false
      authorization_policy: two_factor
      redirect_uris:
        - https://portainer.domain.com
      scopes:
        - openid
        - profile
        - groups
        - email
      userinfo_signed_response_alg: none
```


### Build Information


```shell
Last Tag: v4.38.16
State: tagged clean
Branch: v4.38.16
Commit: 83023d051500e5073acb468b67b90a84ce958ea8
Build Number: 33895
Build OS: linux
Build Arch: amd64
Build Compiler: gc
Build Date: Sun, 06 Oct 2024 22:18:20 +1100
Extra: 

Go:
    Version: go1.23.1
    Module Path: github.com/authelia/authelia/v4
    Executable Path: github.com/authelia/authelia/v4/cmd/authelia
```


### Logs (Authelia)


```shell
time="2024-10-13T01:00:10+02:00" level=debug msg="Loaded Configuration Sources" files="[/config/configuration.yml]" filters="[]"
time="2024-10-13T01:00:10+02:00" level=debug msg="Logging Initialized" fields.level=debug file= format= keep_stdout=false
time="2024-10-13T01:00:10+02:00" level=debug msg="Process user information" gid=1000 uid=1000
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x5623697789ff]

goroutine 1 [running]:
github.com/authelia/authelia/v4/internal/configuration/validator.validateOIDCIssuerPrivateKeysUseAlg(0x0, 0x0?, 0xc000552c40, 0xc000bbc0f0)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:232 +0x33f
github.com/authelia/authelia/v4/internal/configuration/validator.validateOIDCIssuerJSONWebKeys(0xc000552c40, 0xc000bbc0f0)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:211 +0xdde
github.com/authelia/authelia/v4/internal/configuration/validator.validateOIDCIssuer(0xc000552c40, 0xc000bbc0f0)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:130 +0x35f
github.com/authelia/authelia/v4/internal/configuration/validator.validateOIDC(0xc000ce8180, 0xc000552c40, 0xc000bbc0f0)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:31 +0xe5
github.com/authelia/authelia/v4/internal/configuration/validator.ValidateIdentityProviders(...)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:21
github.com/authelia/authelia/v4/internal/configuration/validator.ValidateConfiguration(0xc000b48508, 0xc000bbc0f0, {0xc0005e5c18, 0x1, 0x56236a6a1368?})
        github.com/authelia/authelia/v4/internal/configuration/validator/configuration.go:66 +0x5ad
github.com/authelia/authelia/v4/internal/commands.(*CmdCtx).HelperConfigValidateRunE(0xc000524270, 0xc000b54008?, {0x562369c675c9?, 0x7?, 0x56236902b812?})
        github.com/authelia/authelia/v4/internal/commands/context.go:238 +0x8c
github.com/authelia/authelia/v4/internal/commands.NewRootCmd.(*CmdCtx).ChainRunE.func1(0xc000b54008, {0x56236b228a00, 0x0, 0x0})
        github.com/authelia/authelia/v4/internal/commands/context.go:186 +0x79
github.com/spf13/cobra.(*Command).execute(0xc000b54008, {0xc000040090, 0x0, 0x0})
        github.com/spf13/cobra@v1.8.1/command.go:970 +0xa24
github.com/spf13/cobra.(*Command).ExecuteC(0xc000b54008)
        github.com/spf13/cobra@v1.8.1/command.go:1117 +0x3ff
github.com/spf13/cobra.(*Command).Execute(0xc0000061c0?)
        github.com/spf13/cobra@v1.8.1/command.go:1041 +0x13
main.main()
        github.com/authelia/authelia/v4/cmd/authelia/main.go:10 +0x18
time="2024-10-13T01:00:10+02:00" level=debug msg="Loaded Configuration Sources" files="[/config/configuration.yml]" filters="[]"
time="2024-10-13T01:00:10+02:00" level=debug msg="Logging Initialized" fields.level=debug file= format= keep_stdout=false
time="2024-10-13T01:00:10+02:00" level=debug msg="Process user information" gid=1000 uid=1000
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x55fa0e6369ff]

goroutine 1 [running]:
github.com/authelia/authelia/v4/internal/configuration/validator.validateOIDCIssuerPrivateKeysUseAlg(0x0, 0x0?, 0xc000105dc0, 0xc000639d10)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:232 +0x33f
github.com/authelia/authelia/v4/internal/configuration/validator.validateOIDCIssuerJSONWebKeys(0xc000105dc0, 0xc000639d10)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:211 +0xdde
github.com/authelia/authelia/v4/internal/configuration/validator.validateOIDCIssuer(0xc000105dc0, 0xc000639d10)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:130 +0x35f
github.com/authelia/authelia/v4/internal/configuration/validator.validateOIDC(0xc00075dda0, 0xc000105dc0, 0xc000639d10)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:31 +0xe5
github.com/authelia/authelia/v4/internal/configuration/validator.ValidateIdentityProviders(...)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:21
github.com/authelia/authelia/v4/internal/configuration/validator.ValidateConfiguration(0xc00031cf08, 0xc000639d10, {0xc00001dc18, 0x1, 0x55fa0f55f368?})
        github.com/authelia/authelia/v4/internal/configuration/validator/configuration.go:66 +0x5ad
github.com/authelia/authelia/v4/internal/commands.(*CmdCtx).HelperConfigValidateRunE(0xc000658410, 0xc00062a008?, {0x55fa0eb255c9?, 0x7?, 0x55fa0dee9812?})
        github.com/authelia/authelia/v4/internal/commands/context.go:238 +0x8c
github.com/authelia/authelia/v4/internal/commands.NewRootCmd.(*CmdCtx).ChainRunE.func1(0xc00062a008, {0x55fa100e6a00, 0x0, 0x0})
        github.com/authelia/authelia/v4/internal/commands/context.go:186 +0x79
github.com/spf13/cobra.(*Command).execute(0xc00062a008, {0xc000164040, 0x0, 0x0})
        github.com/spf13/cobra@v1.8.1/command.go:970 +0xa24
github.com/spf13/cobra.(*Command).ExecuteC(0xc00062a008)
        github.com/spf13/cobra@v1.8.1/command.go:1117 +0x3ff
github.com/spf13/cobra.(*Command).Execute(0xc0000061c0?)
        github.com/spf13/cobra@v1.8.1/command.go:1041 +0x13
main.main()
        github.com/authelia/authelia/v4/cmd/authelia/main.go:10 +0x18
time="2024-10-13T01:00:11+02:00" level=debug msg="Loaded Configuration Sources" files="[/config/configuration.yml]" filters="[]"
time="2024-10-13T01:00:11+02:00" level=debug msg="Logging Initialized" fields.level=debug file= format= keep_stdout=false
time="2024-10-13T01:00:11+02:00" level=debug msg="Process user information" gid=1000 uid=1000
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x5621dc8d39ff]

goroutine 1 [running]:
github.com/authelia/authelia/v4/internal/configuration/validator.validateOIDCIssuerPrivateKeysUseAlg(0x0, 0x0?, 0xc000331500, 0xc0003eecf0)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:232 +0x33f
github.com/authelia/authelia/v4/internal/configuration/validator.validateOIDCIssuerJSONWebKeys(0xc000331500, 0xc0003eecf0)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:211 +0xdde
github.com/authelia/authelia/v4/internal/configuration/validator.validateOIDCIssuer(0xc000331500, 0xc0003eecf0)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:130 +0x35f
github.com/authelia/authelia/v4/internal/configuration/validator.validateOIDC(0xc0005fed80, 0xc000331500, 0xc0003eecf0)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:31 +0xe5
github.com/authelia/authelia/v4/internal/configuration/validator.ValidateIdentityProviders(...)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:21
github.com/authelia/authelia/v4/internal/configuration/validator.ValidateConfiguration(0xc000320f08, 0xc0003eecf0, {0xc0006edc18, 0x1, 0x5621dd7fc368?})
        github.com/authelia/authelia/v4/internal/configuration/validator/configuration.go:66 +0x5ad
github.com/authelia/authelia/v4/internal/commands.(*CmdCtx).HelperConfigValidateRunE(0xc0004a1040, 0xc0006a8608?, {0x5621dcdc25c9?, 0x7?, 0x5621dc186812?})
        github.com/authelia/authelia/v4/internal/commands/context.go:238 +0x8c
github.com/authelia/authelia/v4/internal/commands.NewRootCmd.(*CmdCtx).ChainRunE.func1(0xc0006a8608, {0x5621de383a00, 0x0, 0x0})
        github.com/authelia/authelia/v4/internal/commands/context.go:186 +0x79
github.com/spf13/cobra.(*Command).execute(0xc0006a8608, {0xc000040090, 0x0, 0x0})
        github.com/spf13/cobra@v1.8.1/command.go:970 +0xa24
github.com/spf13/cobra.(*Command).ExecuteC(0xc0006a8608)
        github.com/spf13/cobra@v1.8.1/command.go:1117 +0x3ff
github.com/spf13/cobra.(*Command).Execute(0xc0000061c0?)
        github.com/spf13/cobra@v1.8.1/command.go:1041 +0x13
main.main()
        github.com/authelia/authelia/v4/cmd/authelia/main.go:10 +0x18
time="2024-10-13T01:00:11+02:00" level=debug msg="Loaded Configuration Sources" files="[/config/configuration.yml]" filters="[]"
time="2024-10-13T01:00:11+02:00" level=debug msg="Logging Initialized" fields.level=debug file= format= keep_stdout=false
time="2024-10-13T01:00:11+02:00" level=debug msg="Process user information" gid=1000 uid=1000
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x556f6a2819ff]

goroutine 1 [running]:
github.com/authelia/authelia/v4/internal/configuration/validator.validateOIDCIssuerPrivateKeysUseAlg(0x0, 0x0?, 0xc00058a8c0, 0xc0009560f0)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:232 +0x33f
github.com/authelia/authelia/v4/internal/configuration/validator.validateOIDCIssuerJSONWebKeys(0xc00058a8c0, 0xc0009560f0)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:211 +0xdde
github.com/authelia/authelia/v4/internal/configuration/validator.validateOIDCIssuer(0xc00058a8c0, 0xc0009560f0)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:130 +0x35f
github.com/authelia/authelia/v4/internal/configuration/validator.validateOIDC(0xc000c90180, 0xc00058a8c0, 0xc0009560f0)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:31 +0xe5
github.com/authelia/authelia/v4/internal/configuration/validator.ValidateIdentityProviders(...)
        github.com/authelia/authelia/v4/internal/configuration/validator/identity_providers.go:21
github.com/authelia/authelia/v4/internal/configuration/validator.ValidateConfiguration(0xc0008de508, 0xc0009560f0, {0xc000551c18, 0x1, 0x556f6b1aa368?})
        github.com/authelia/authelia/v4/internal/configuration/validator/configuration.go:66 +0x5ad
github.com/authelia/authelia/v4/internal/commands.(*CmdCtx).HelperConfigValidateRunE(0xc0005b2340, 0xc0008ea008?, {0x556f6a7705c9?, 0x7?, 0x556f69b34812?})
        github.com/authelia/authelia/v4/internal/commands/context.go:238 +0x8c
github.com/authelia/authelia/v4/internal/commands.NewRootCmd.(*CmdCtx).ChainRunE.func1(0xc0008ea008, {0x556f6bd31a00, 0x0, 0x0})
        github.com/authelia/authelia/v4/internal/commands/context.go:186 +0x79
github.com/spf13/cobra.(*Command).execute(0xc0008ea008, {0xc000040090, 0x0, 0x0})
        github.com/spf13/cobra@v1.8.1/command.go:970 +0xa24
github.com/spf13/cobra.(*Command).ExecuteC(0xc0008ea008)
        github.com/spf13/cobra@v1.8.1/command.go:1117 +0x3ff
github.com/spf13/cobra.(*Command).Execute(0xc0000061c0?)
        github.com/spf13/cobra@v1.8.1/command.go:1041 +0x13
main.main()
        github.com/authelia/authelia/v4/cmd/authelia/main.go:10 +0x18
```


### Logs (Proxy / Application)


_No response_

### Documentation


_No response_

### Pre-Submission Checklist


- [X] I agree to follow the [Code of Conduct](http://www.authelia.com/code-of-conduct)

- [X] This is a bug report and not a support request

- [X] I have read the security policy and this bug report is not a security issue or security related issue

- [X] I have either included the complete configuration file or I am sure it's unrelated to the configuration

- [X] I have either included the complete debug / trace logs or the output of the build-info command if the logs are not relevant

- [X] I have provided all of the required information in full with the only alteration being reasonable sanitization in accordance with the [Troubleshooting Sanitization](https://www.authelia.com/r/sanitize) reference guide

- [X] I have checked for related proxy or application logs and included them if available

- [X] I have checked for related issues and checked the documentation


Pull request description:
fix(configuration): jwk without required key startup panic
This fixes an issue where not defining the required key for a JSON Web Key would cause a panic.

Fixes #8020

Patch:
diff --git a/internal/configuration/validator/const.go b/internal/configuration/validator/const.go
index 7cfc50f36..b33b173d6 100644
--- a/internal/configuration/validator/const.go
+++ b/internal/configuration/validator/const.go
@@ -174,6 +174,8 @@ const (
 	errFmtOIDCProviderInsecureDisabledParameterEntropy = errFmtOIDCProviderInsecureParameterEntropy +
 		"disabled which is considered unsafe and insecure"
 	errFmtOIDCProviderPrivateKeysInvalid                 = "identity_providers: oidc: jwks: key #%d: option 'key' must be a valid private key but the provided data is malformed as it's missing the public key bits"
+	errFmtOIDCProviderPrivateKeysMissing                 = "identity_providers: oidc: jwks: key #%d: option 'key' must be provided"
+	errFmtOIDCProviderPrivateKeysWithKeyID               = "identity_providers: oidc: jwks: key #%d with key id '%s': option 'key' must be provided"
 	errFmtOIDCProviderPrivateKeysCalcThumbprint          = "identity_providers: oidc: jwks: key #%d: option 'key' failed to calculate thumbprint to configure key id value: %w"
 	errFmtOIDCProviderPrivateKeysKeyIDLength             = "identity_providers: oidc: jwks: key #%d with key id '%s': option `key_id` must be 100 characters or less"
 	errFmtOIDCProviderPrivateKeysAttributeNotUnique      = "identity_providers: oidc: jwks: key #%d with key id '%s': option '%s' must be unique"
@@ -286,17 +288,18 @@ const (
 	errFmtOIDCClientInvalidRefreshTokenOptionWithoutCodeResponseType = errFmtOIDCClientOption +
 		"'%s' should only have the values %s if the client is also configured with a 'response_type' such as %s which respond with authorization codes"
 
-	errFmtOIDCClientPublicKeysBothURIAndValuesConfigured  = "identity_providers: oidc: clients: client '%s': option 'jwks_uri' must not be defined at the same time as option 'jwks'"
-	errFmtOIDCClientPublicKeysURIInvalidScheme            = "identity_providers: oidc: clients: client '%s': option 'jwks_uri' must have the 'https' scheme but the scheme is '%s'"
-	errFmtOIDCClientPublicKeysProperties                  = "identity_providers: oidc: clients: client '%s': jwks: key #%d with key id '%s': option 'key' failed to get key properties: %w"
-	errFmtOIDCClientPublicKeysInvalidOptionOneOf          = "identity_providers: oidc: clients: client '%s': jwks: key #%d with key id '%s': option '%s' must be one of %s but it's configured as '%s'"
-	errFmtOIDCClientPublicKeysInvalidOptionMissingOneOf   = "identity_providers: oidc: clients: client '%s': jwks: key #%d: option '%s' must be provided"
-	errFmtOIDCClientPublicKeysKeyMalformed                = "identity_providers: oidc: clients: client '%s': jwks: key #%d: option 'key' option 'key' must be a valid private key but the provided data is malformed as it's missing the public key bits"
-	errFmtOIDCClientPublicKeysRSAKeyLessThan2048Bits      = "identity_providers: oidc: clients: client '%s': jwks: key #%d with key id '%s': option 'key' is an RSA %d bit private key but it must at minimum be a RSA 2048 bit private key"
-	errFmtOIDCClientPublicKeysKeyNotRSAOrECDSA            = "identity_providers: oidc: clients: client '%s': jwks: key #%d with key id '%s': option 'key' must be a RSA public key or ECDSA public key but it's type is %T"
-	errFmtOIDCClientPublicKeysCertificateChainKeyMismatch = "identity_providers: oidc: clients: client '%s': jwks: key #%d with key id '%s': option 'certificate_chain' does not appear to contain the public key for the public key provided by option 'key'"
-	errFmtOIDCClientPublicKeysCertificateChainInvalid     = "identity_providers: oidc: clients: client '%s': jwks: key #%d with key id '%s': option 'certificate_chain' produced an error during validation of the chain: %w"
-	errFmtOIDCClientPublicKeysROSAMissingAlgorithm        = errFmtOIDCClientOption + "'request_object_signing_alg' must be one of %s configured in the client option 'jwks'"
+	errFmtOIDCClientPublicKeysBothURIAndValuesConfigured      = "identity_providers: oidc: clients: client '%s': option 'jwks_uri' must not be defined at the same time as option 'jwks'"
+	errFmtOIDCClientPublicKeysURIInvalidScheme                = "identity_providers: oidc: clients: client '%s': option 'jwks_uri' must have the 'https' scheme but the scheme is '%s'"
+	errFmtOIDCClientPublicKeysProperties                      = "identity_providers: oidc: clients: client '%s': jwks: key #%d with key id '%s': option 'key' failed to get key properties: %w"
+	errFmtOIDCClientPublicKeysInvalidOptionOneOf              = "identity_providers: oidc: clients: client '%s': jwks: key #%d with key id '%s': option '%s' must be one of %s but it's configured as '%s'"
+	errFmtOIDCClientPublicKeysInvalidOptionMissingOneOf       = "identity_providers: oidc: clients: client '%s': jwks: key #%d: option '%s' must be provided"
+	errFmtOIDCClientPublicKeysWithIDInvalidOptionMissingOneOf = "identity_providers: oidc: clients: client '%s': jwks: key #%d with key id '%s': option '%s' must be provided"
+	errFmtOIDCClientPublicKeysKeyMalformed                    = "identity_providers: oidc: clients: client '%s': jwks: key #%d: option 'key' option 'key' must be a valid private key but the provided data is malformed as it's missing the public key bits"
+	errFmtOIDCClientPublicKeysRSAKeyLessThan2048Bits          = "identity_providers: oidc: clients: client '%s': jwks: key #%d with key id '%s': option 'key' is an RSA %d bit private key but it must at minimum be a RSA 2048 bit private key"
+	errFmtOIDCClientPublicKeysKeyNotRSAOrECDSA                = "identity_providers: oidc: clients: client '%s': jwks: key #%d with key id '%s': option 'key' must be a RSA public key or ECDSA public key but it's type is %T"
+	errFmtOIDCClientPublicKeysCertificateChainKeyMismatch     = "identity_providers: oidc: clients: client '%s': jwks: key #%d with key id '%s': option 'certificate_chain' does not appear to contain the public key for the public key provided by option 'key'"
+	errFmtOIDCClientPublicKeysCertificateChainInvalid         = "identity_providers: oidc: clients: client '%s': jwks: key #%d with key id '%s': option 'certificate_chain' produced an error during validation of the chain: %w"
+	errFmtOIDCClientPublicKeysROSAMissingAlgorithm            = errFmtOIDCClientOption + "'request_object_signing_alg' must be one of %s configured in the client option 'jwks'"
 )
 
 // WebAuthn Error constants.
diff --git a/internal/configuration/validator/identity_providers.go b/internal/configuration/validator/identity_providers.go
index 2ee43321f..1f5cd2f5e 100644
--- a/internal/configuration/validator/identity_providers.go
+++ b/internal/configuration/validator/identity_providers.go
@@ -175,6 +175,16 @@ func validateOIDCIssuerJSONWebKeys(config *schema.IdentityProvidersOpenIDConnect
 	config.Discovery.DefaultKeyIDs = map[string]string{}
 
 	for i := 0; i < len(config.JSONWebKeys); i++ {
+		if config.JSONWebKeys[i].Key == nil {
+			if len(config.JSONWebKeys[i].KeyID) != 0 {
+				validator.Push(fmt.Errorf(errFmtOIDCProviderPrivateKeysWithKeyID, i+1, config.JSONWebKeys[i].KeyID))
+			} else {
+				validator.Push(fmt.Errorf(errFmtOIDCProviderPrivateKeysMissing, i+1))
+			}
+
+			continue
+		}
+
 		if key, ok := config.JSONWebKeys[i].Key.(*rsa.PrivateKey); ok && key.PublicKey.N == nil {
 			validator.Push(fmt.Errorf(errFmtOIDCProviderPrivateKeysInvalid, i+1))
 
@@ -510,13 +520,21 @@ func validateOIDCClientJSONWebKeysList(c int, config *schema.IdentityProvidersOp
 			continue
 		}
 
+		if config.Clients[c].JSONWebKeys[i].Key == nil {
+			if len(config.Clients[c].JSONWebKeys[i].KeyID) != 0 {
+				validator.Push(fmt.Errorf(errFmtOIDCClientPublicKeysWithIDInvalidOptionMissingOneOf, config.Clients[c].ID, i+1, config.Clients[c].JSONWebKeys[i].KeyID, attrOIDCKey))
+			} else {
+				validator.Push(fmt.Errorf(errFmtOIDCClientPublicKeysInvalidOptionMissingOneOf, config.Clients[c].ID, i+1, attrOIDCKey))
+			}
+
+			continue
+		}
+
 		validateOIDCClientJSONWebKeysListKeyUseAlg(c, i, props, config, validator)
 
 		var checkEqualKey bool
 
 		switch key := config.Clients[c].JSONWebKeys[i].Key.(type) {
-		case nil:
-			validator.Push(fmt.Errorf(errFmtOIDCClientPublicKeysInvalidOptionMissingOneOf, config.Clients[c].ID, i+1, attrOIDCKey))
 		case *rsa.PublicKey:
 			checkEqualKey = true
 


Test patch:
diff --git a/internal/configuration/provider_test.go b/internal/configuration/provider_test.go
index 6111a2ee5..ee679aac3 100644
--- a/internal/configuration/provider_test.go
+++ b/internal/configuration/provider_test.go
@@ -527,6 +527,31 @@ func TestShouldLoadURLList(t *testing.T) {
 	assert.Equal(t, "https://example.com", config.IdentityProviders.OIDC.CORS.AllowedOrigins[1].String())
 }
 
+func TestShouldNotPanicJWKNilKey(t *testing.T) {
+	val := schema.NewStructValidator()
+	keys, config, err := Load(val, NewDefaultSources([]string{"./test_resources/config_oidc_empty_jwk_key.yml"}, DefaultEnvPrefix, DefaultEnvDelimiter)...)
+
+	assert.NoError(t, err)
+
+	validator.ValidateKeys(keys, GetMultiKeyMappedDeprecationKeys(), DefaultEnvPrefix, val)
+
+	assert.Len(t, val.Errors(), 0)
+	assert.Len(t, val.Warnings(), 0)
+
+	require.NotPanics(t, func() {
+		validator.ValidateIdentityProviders(validator.NewValidateCtx(), &config.IdentityProviders, val)
+	})
+
+	assert.Len(t, val.Errors(), 5)
+	require.Len(t, val.Warnings(), 1)
+
+	assert.EqualError(t, val.Errors()[0], "identity_providers: oidc: jwks: key #1 with key id 'abc': option 'key' must be provided")
+	assert.EqualError(t, val.Errors()[1], "identity_providers: oidc: jwks: key #2: option 'key' must be provided")
+	assert.EqualError(t, val.Errors()[2], "identity_providers: oidc: clients: client 'abc': jwks: key #1 with key id 'client_abc': option 'key' must be provided")
+	assert.EqualError(t, val.Errors()[3], "identity_providers: oidc: clients: client 'abc': jwks: key #2: option 'key_id' must be provided")
+	assert.EqualError(t, val.Errors()[4], "identity_providers: oidc: clients: client 'abc': jwks: key #2: option 'key' must be provided")
+}
+
 func TestShouldDisableOIDCEntropy(t *testing.T) {
 	val := schema.NewStructValidator()
 	keys, config, err := Load(val, NewDefaultSources([]string{"./test_resources/config_oidc_disable_entropy.yml"}, DefaultEnvPrefix, DefaultEnvDelimiter)...)
diff --git a/internal/configuration/test_resources/config_oidc_empty_jwk_key.yml b/internal/configuration/test_resources/config_oidc_empty_jwk_key.yml
new file mode 100644
index 000000000..9e3281c14
--- /dev/null
+++ b/internal/configuration/test_resources/config_oidc_empty_jwk_key.yml
@@ -0,0 +1,144 @@
+---
+default_redirection_url: 'https://home.example.com:8080/'
+
+server:
+  address: 'tcp://127.0.0.1:9091'
+
+log:
+  level: 'debug'
+
+totp:
+  issuer: 'authelia.com'
+
+duo_api:
+  hostname: 'api-123456789.example.com'
+  integration_key: 'ABCDEF'
+
+authentication_backend:
+  ldap:
+    address: 'ldap://127.0.0.1'
+    base_dn: 'dc=example,dc=com'
+    additional_users_dn: 'ou=users'
+    users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
+    additional_groups_dn: 'ou=groups'
+    groups_filter: '(&(member={dn})(objectClass=groupOfNames))'
+    user: 'cn=admin,dc=example,dc=com'
+    attributes:
+      username: 'uid'
+      group_name: 'cn'
+      mail: 'mail'
+
+access_control:
+  default_policy: 'deny'
+
+  rules:
+    # Rules applied to everyone
+    - domain: 'public.example.com'
+      policy: 'bypass'
+
+    - domain: 'secure.example.com'
+      policy: 'one_factor'
+      # Network based rule, if not provided any network matches.
+      networks:
+        - '192.168.1.0/24'
+    - domain: 'secure.example.com'
+      policy: 'two_factor'
+
+    - domain: ['singlefactor.example.com', 'onefactor.example.com']
+      policy: 'one_factor'
+
+    # Rules applied to 'admins' group
+    - domain: 'mx2.mail.example.com'
+      subject: 'group:admins'
+      policy: 'deny'
+    - domain: '*.example.com'
+      subject: 'group:admins'
+      policy: 'two_factor'
+
+    # Rules applied to 'dev' group
+    - domain: 'dev.example.com'
+      resources:
+        - '^/groups/dev/.*$'
+      subject: 'group:dev'
+      policy: 'two_factor'
+
+    # Rules applied to user 'john'
+    - domain: 'dev.example.com'
+      resources:
+        - '^/users/john/.*$'
+      subject: 'user:john'
+      policy: 'two_factor'
+
+    # Rules applied to 'dev' group and user 'john'
+    - domain: 'dev.example.com'
+      resources:
+        - '^/deny-all.*$'
+      subject: ['group:dev', 'user:john']
+      policy: 'deny'
+
+    # Rules applied to user 'harry'
+    - domain: 'dev.example.com'
+      resources:
+        - '^/users/harry/.*$'
+      subject: 'user:harry'
+      policy: 'two_factor'
+
+    # Rules applied to user 'bob'
+    - domain: '*.mail.example.com'
+      subject: 'user:bob'
+      policy: 'two_factor'
+    - domain: 'dev.example.com'
+      resources:
+        - '^/users/bob/.*$'
+      subject: 'user:bob'
+      policy: 'two_factor'
+
+session:
+  name: 'authelia_session'
+  expiration: '1h'  # 1 hour
+  inactivity: '5m'  # 5 minutes
+  domain: 'example.com'
+  redis:
+    host: '127.0.0.1'
+    port: 6379
+    high_availability:
+      sentinel_name: 'test'
+
+regulation:
+  max_retries: 3
+  find_time: '2m'
+  ban_time: '5m'
+
+storage:
+  mysql:
+    address: 'tcp://127.0.0.1:3306'
+    database: 'authelia'
+    username: 'authelia'
+
+notifier:
+  smtp:
+    address: 'smtp://127.0.0.1:1025'
+    username: 'test'
+    sender: 'admin@example.com'
+    disable_require_tls: true
+
+identity_providers:
+  oidc:
+    cors:
+      allowed_origins:
+        - 'https://google.com'
+        - 'https://example.com'
+    jwks:
+      - key_id: 'abc'
+        use: 'sig'
+      - use: 'sig'
+    clients:
+      - client_id: 'abc'
+        client_secret: '123'
+        consent_mode: 'explicit'
+        userinfo_signed_response_alg: 'none'
+        jwks:
+          - key_id: 'client_abc'
+            use: 'sig'
+          - use: 'sig'
+...
diff --git a/internal/configuration/validator/identity_providers_test.go b/internal/configuration/validator/identity_providers_test.go
index d1a9d70d8..9f7c2f83f 100644
--- a/internal/configuration/validator/identity_providers_test.go
+++ b/internal/configuration/validator/identity_providers_test.go
@@ -3202,6 +3202,19 @@ func TestValidateOIDCClientJWKS(t *testing.T) {
 			nil,
 			nil,
 			[]string{
+				"identity_providers: oidc: clients: client 'test': jwks: key #1 with key id 'test': option 'key' must be provided",
+			},
+		},
+		{
+			"ShouldFailOnEmptyKeyNoKeyID",
+			nil,
+			[]schema.JWK{
+				{KeyID: "", Use: oidc.KeyUseSignature, Algorithm: oidc.SigningAlgRSAUsingSHA256, Key: nil},
+			},
+			nil,
+			nil,
+			[]string{
+				"identity_providers: oidc: clients: client 'test': jwks: key #1: option 'key_id' must be provided",
 				"identity_providers: oidc: clients: client 'test': jwks: key #1: option 'key' must be provided",
 			},
 		},
@@ -3552,6 +3565,44 @@ func TestValidateOIDCIssuer(t *testing.T) {
 				"identity_providers: oidc: jwks: keys: must at least have one key supporting the 'RS256' algorithm but only has 'invalid'",
 			},
 		},
+		{
+			"ShouldErrorNilKeyWithoutKID",
+			&schema.IdentityProvidersOpenIDConnect{
+				JSONWebKeys: []schema.JWK{
+					{Key: nil, Algorithm: oidc.SigningAlgRSAUsingSHA256, Use: oidc.KeyUseSignature},
+				},
+			},
+			schema.IdentityProvidersOpenIDConnect{
+				JSONWebKeys: []schema.JWK{
+					{Algorithm: oidc.SigningAlgRSAUsingSHA256, Use: oidc.KeyUseSignature},
+				},
+				Discovery: schema.IdentityProvidersOpenIDConnectDiscovery{
+					DefaultKeyIDs: map[string]string{},
+				},
+			},
+			[]string{
+				"identity_providers: oidc: jwks: key #1: option 'key' must be provided",
+			},
+		},
+		{
+			"ShouldErrorNilKey",
+			&schema.IdentityProvidersOpenIDConnect{
+				JSONWebKeys: []schema.JWK{
+					{Key: nil, KeyID: "example", Algorithm: oidc.SigningAlgRSAUsingSHA256, Use: oidc.KeyUseSignature},
+				},
+			},
+			schema.IdentityProvidersOpenIDConnect{
+				JSONWebKeys: []schema.JWK{
+					{KeyID: "example", Algorithm: oidc.SigningAlgRSAUsingSHA256, Use: oidc.KeyUseSignature},
+				},
+				Discovery: schema.IdentityProvidersOpenIDConnectDiscovery{
+					DefaultKeyIDs: map[string]string{},
+				},
+			},
+			[]string{
+				"identity_providers: oidc: jwks: key #1 with key id 'example': option 'key' must be provided",
+			},
+		},
 		{
 			"ShouldRaiseErrorOnBadUse",
 			&schema.IdentityProvidersOpenIDConnect{