Unauthorized error OpenID with Autentik

Versions (Open Search v3.2.0)

Describe the issue:
I’m configuring OpenID authentication on opensearch/opensearch dashboards. I’m attaching the configurations. The SSO backend is authentik. I’m getting the error {“statusCode”:401,“error”:“Unauthorized”,“message”:“Unauthorized”}
Despite the debug logs, I can’t figure out the problem. Authentication appears to be occurring correctly. I’m not seeing any errors related to the endpoint being unreachable.
I tried returning the role scope as “all_access” or “kibana_server” as per the role_mapping file, but it didn’t work.The error in the opensearch log is

\[2025-10-06T17:33:32,109\]\[DEBUG\]\[o.o.s.a.BackendRegistry \] \[node.domain.com\] Check authdomain for rest internal/0 or 2 in total
\[2025-10-06T17:33:32,109\]\[DEBUG\]\[o.o.s.a.BackendRegistry \] \[node.domain.com\] Check authdomain for rest noop/1 or 2 in total
\[2025-10-06T17:33:32,109\]\[DEBUG\]\[o.o.s.a.BackendRegistry \] \[node.domain.com\] User still not authenticated after checking 2 auth domains
\[2025-10-06T17:33:32,110\]\[WARN \]\[o.o.s.a.BackendRegistry \] \[node.domain.com\] Authentication finally failed for null from 127.0.0.1:36870

How can I fix it? Ty

Configuration:
config.yml opensearch

config:
  dynamic:
    http:
      anonymous_auth_enabled: false
    authc:
      basic_internal_auth_domain:
        description: "Authenticate via HTTP Basic against internal users database"
        http_enabled: true
        transport_enabled: true
        order: 0
        http_authenticator:
          type: basic
          challenge: false
        authentication_backend:
          type: internal

      openid_auth_domain:
        description: "Authenticate via OpenID Authentik"
        http_enabled: true
        transport_enabled: false
        order: 1
        http_authenticator:
          type: openid
          challenge: false
          config:
            subject_key: preferred_username
            roles_key: roles
            enable_ssl: true
            pemtrustedcas_content: |-
              -----BEGIN CERTIFICATE-----
              MIIEVjCCAnYXFUxpNjTWPKpagDHJQmqrAcDmWJnMsFY3jS
              ....
              u1igv3OefnWjSQ==
              -----END CERTIFICATE-----
            openid_connect_url: https://auth.domain.com/application/o/opensearch-ca/.well-known/openid-configuration    
        authentication_backend:
          type: noop

roles_mapping.yml

_meta:
  type: "rolesmapping"
  config_version: 2

all_access:
  reserved: false
  backend_roles:
  - "admin"
  description: "Maps admin to all_access"

  kibana_server:
  reserved: true
  users:
  - "kibanaserver"

opensearch_dashboards.yml

opensearch_security.auth.type: "openid"
opensearch_security.openid.connect_url: "https://auth.domain.com/application/o/opensearch-ca/.well-known/openid-configuration"
opensearch_security.openid.client_id: "***"
opensearch_security.openid.client_secret: "***"
opensearch_security.openid.base_redirect_url: "https://domain.company.com"
opensearch_security.openid.scope: "openid profile email roles"
opensearch_security.openid.header: "Authorization"
opensearch_security.cookie.secure: true
opensearch_security.auth.multiple_auth_enabled: true

Relevant Logs or Screenshots:
image

@antekronos Could you share your full opensearch_dashboards.yml file?

The full opensearch_dashboards.yml

---

server.port: 15061

server.host: "0.0.0.0"

server.name: "osearch.domain.com"

opensearch.hosts: ["https://osearch-ca1.domain.com:9200"]

server.ssl.enabled: false
server.ssl.certificate: /etc/ssl/certs/domain.com/wildcard.domain.com.crt
server.ssl.key: /etc/ssl/certs/domain.com/wildcard.domain.com.key

opensearch.ssl.certificateAuthorities: [ "/etc/ssl/certs/ca-certificates.crt"]

opensearch.ssl.verificationMode: none

logging.dest: /var/log/opensearch-dashboards/opensearch_dashboards.log

logging.verbose: true

opensearch.username: kibanaserver
opensearch.password: ***
opensearch.requestHeadersWhitelist: ["Authorization", "securitytenant"]


opensearch_security.multitenancy.enabled: true
opensearch_security.multitenancy.tenants.preferred: [Private, Global]
opensearch_security.readonly_mode.roles: [kibana_read_only]


opensearch_security.auth.type: "openid"
opensearch_security.openid.connect_url: "https://auth.domain.com/application/o/opensearch-ca/.well-known/openid-configuration"
opensearch_security.openid.client_id: "***"
opensearch_security.openid.client_secret: "***"
opensearch_security.openid.base_redirect_url: "https://osearch.domain.com"
opensearch_security.openid.scope: "openid profile email roles"
opensearch_security.openid.header: "Authorization"
opensearch_security.cookie.secure: true
opensearch_security.auth.multiple_auth_enabled: true


logging:
  appenders:
    default:
      type: console
      layout:
        type: pattern
        pattern: "[%date][%level][%logger] %message"
  root:
    level: debug
  loggers:
    - context: plugins.security
      level: debug
    - context: security
      level: debug

@antekronos I’ve got Authentik working with OpenSearch but I used ‘groups’ instead of ‘roles’ as roles_key in config.yml.

Also, if you’re using a proxy, be sure that all headers from opensearch.requestHeadersWhitelist are passed.

Last one, please replace opensearch.requestHeadersWhitelist with opensearch.requestHeadersAllowlist as opensearch.requestHeadersWhitelist is deprecated.

I’ve already tried using groups instead of roles, but the error doesn’t change.
I’m attaching the current contents of roles_mapping and roles. I want to match the groups “admins” with the roles all_access. Is there something I’m doing wrong?
I modified opensearch.requestHeadersAllowlist as indicated.

roles_mapping.yml

_meta:
  type: "rolesmapping"
  config_version: 2


all_access:
  reserved: false
  backend_roles:
  - "admin"
  hosts: []
  users:
    - "admins"
  description: "Maps admin to all_access"

admins:
  reserved: false
  backend_roles:
  - "admin"
  hosts: []
  users:
    - "admins"
  description: "Maps admin to all_access"

@antekronos, Your backend_roles in mappings refer only to admin. Does your Authentik’s user has an admin group/role assigned?
If not, then Authentik’s group should be included in the backend_roles.

If this is a dev/test environment, you can set users to * in the all_access and then check through Dev tools what groups were passed from Authentik

GET _plugins/_security/authinfo

@pablo Yes, my user has an admins group associated with it, i’ve added to the configuration
I tried changing the configuration as indicated.

all_access:
reserved: false
backend_roles:
- "admins"
- "admin"
hosts: []
users:
- "*"
description: "Maps admin to all_access"

Without successfully logging in

I was unable to find the groups returned by authentik using the dev tools.

By contacting the URL /_plugins/_security/authinfo on the opensearch endpoint, I get

Authentication finally failed

It would be helpful to be able to dump the obtained jwt into the logs

If its an authentication issue, then roles mappings do not matter so focus on authentication. It sounds like the tokens from the IdP are getting dropped. Is there a proxy in the mix?

I don’t think it matters, but when you enable multi auth you should be defining the sign in options as a list.

opensearch_security.auth.type: ["openid"]
opensearch_security.auth.multiple_auth_enabled: true
1 Like

I found the solution!
Opensearch doesn’t handle encryption on the JWT token, the token generated by Authentik was in JWE format. I disabled encryption, and Opensearch was able to read the scopes.
I’ll point you to my documentation for anyone who might need it in the future.

/etc/opensearch/opensearch-security/config.yml

_meta:
  type: "config"
  config_version: 2

config:
  dynamic:
    http:
      anonymous_auth_enabled: false
    authc:
      basic_internal_auth_domain:
        description: "Authenticate via HTTP Basic against internal users database"
        http_enabled: true
        transport_enabled: true
        order: 0
        http_authenticator:
          type: basic
          challenge: false
        authentication_backend:
          type: internal

      openid_auth_domain:
        description: "Authenticate via OpenID Authentik"
        http_enabled: true
        transport_enabled: true
        order: 1
        http_authenticator:
          type: openid
          challenge: false
          config:
            subject_key: preferred_username
            roles_key: groups
            openid_connect_idp.enable_ssl: true
            openid_connect_idp.pemtrustedcas_filepath: /etc/ssl/certs/ca-certificates.crt
            required_audience: ***
            openid_connect_url: https://auth.domain.com/application/o/opensearch-ca/.well-known/openid-configuration
        authentication_backend:
          type: noop

My identity provider uses a Let’s Encrypt certificate; the root CA is contained in /etc/ssl/certs/ca-certificates.crt

/etc/opensearch-dashboards/opensearch_dashboards.yml

opensearch.requestHeadersAllowlist: ["Authorization", "securitytenant"]
opensearch_security.multitenancy.enabled: true
opensearch_security.multitenancy.tenants.preferred: [Private, Global]
opensearch_security.readonly_mode.roles: [kibana_read_only]


#OpenID authentication - Authentik
opensearch_security.auth.type: "openid"
opensearch_security.openid.connect_url: "https://auth.domain.com/application/o/opensearch-ca/.well-known/openid-configuration"
opensearch_security.openid.client_id: "***"
opensearch_security.openid.client_secret: "***"
opensearch_security.openid.base_redirect_url: "https://osearch.domain.com"
opensearch_security.openid.scope: "openid profile email"
opensearch_security.openid.header: "Authorization"
opensearch_security.cookie.secure: "true"

In the multi-auth configuration, I kept both OpenID and BasicAuth as a fallback in case of problems with OpenID. Now I’m using only OpenID without any problems.

Please note that JWT tokens are only signed but do not use encryption.
I’m using Caddy as a reverse proxy for dashboards without any problems.