Hi, we've been using kratos (and hydra) for a long...
# ory-selfhosting
w
Hi, we've been using kratos (and hydra) for a long time in our project, and it's mostly been working well. Recently we were notified that some users have problems logging in, getting a 2FA screen while they never set that up (and it's not required). I'm still working with them to debug this. I already noticed though that 1. Many users have an
identity_credentials
entry of
webauthn
type although they've likely never enrolled for any 2FA. The
config
in that database row is very limited, containing only a
user_handle
field. 2. When I create a new user (through kratos client api), the resulting object (as returned through kratos api) has both
password
and
webauthn
objects under
credentials
, even though neither is set -- the user has obviously never even logged in at that point, let alone enrolled in webauthn. Is this all expected or is any of this sign of a wrong setup?
BTW I tried to sign in for one of the users with this
user_handle
webauthn config, and I was not asked for a second factor, so it seems kratos does not see it as a real webauthn enrollment. So 1. might not be the cause of the login problems, but it still seems fishy.
s
Kratos "reserves" the webauthn usernames, so that the user can later set it up.
Same for the password type, we reserve the identifier so that it is not possible to have two identities with the same email/username/...
To help debug this, I'd need the config and also the rows of the affected users.
👀 1
w
Hi @steep-lamp-91158, thanks for your reply. It helps to know why these entries are created early and that it's not a sign of a problem. Here's the redacted kratos config (in yaml format as passed to the helm chart):
Copy code
kratos:
  automigration:
    enabled: true
  config:
    courier:
      smtp:
        connection_uri: smtp://[...]
        from_address: [...]
      template_override_path: /conf/courier-templates
    dsn: mysql://[...]
    identity:
      default_schema_id: default
      schemas:
      - id: default
        url: file:///etc/config/identity.default.schema.json
    log:
      level: info
    secrets:
      session:
      - [...]
    selfservice:
      allowed_return_urls:
      - https://[...]
      - https://[...]
      default_browser_return_url: https://[...]/web/login
      flows:
        error:
          ui_url: https://[...]/web/error
        login:
          after:
            hooks:
            - config:
                auth:
                  config:
                    in: header
                    name: Authorization
                    value: [...]
                  type: api_key
                body: <base64://ZnVuY3Rpb24oY3R4KSB7CiAgdXNlcl9pZDogY3R4LmlkZW50aXR5LmlkCn0K>
                method: POST
                response:
                  ignore: true
                url: <http://dashboard-backend:80/api/v1/users/login_complete>
              hook: web_hook
          ui_url: https://[...]/web/login
        recovery:
          after:
            hooks:
            - config:
                auth:
                  config:
                    in: header
                    name: Authorization
                    value: [...]
                  type: api_key
                body: <base64://ZnVuY3Rpb24oY3R4KSB7CiAgdXNlcl9pZDogY3R4LmlkZW50aXR5LmlkCn0K>
                method: POST
                response:
                  ignore: true
                url: <http://dashboard-backend:80/api/v1/users/recovery_complete>
              hook: web_hook
          enabled: true
          lifespan: 1h
          ui_url: https://[...]/web/recovery
          use: link
        registration:
          ui_url: https://[...]/web/registration
        settings:
          required_aal: highest_available
          ui_url: https://[...]/web/settings
      methods:
        link:
          enabled: true
        totp:
          config:
            issuer: [...]
          enabled: true
        webauthn:
          config:
            passwordless: false
            rp:
              display_name: DISPLAY_NAME
              id: [...]
              origin: https://[...]
          enabled: true
    serve:
      public:
        base_url: https://[...]/kratos/
  emailTemplates:
    recovery:
      invalid:
        body: |-
          [...]
      valid:
        body: |-
          [...]
        plainBody: |-
          [...]
        subject: [...]
    verification:
      invalid:
        body: |-
          [...]
        plainBody: |-
          [...]
        subject: Somebody tried to verify your email address
      valid:
        body: |-
          [...]
        plainBody: [...]
        subject: Please verify your email address
  identitySchemas:
    identity.default.schema.json: |
      {
        "$schema": "<http://json-schema.org/draft-07/schema#>",
        "title": "Person",
        "type": "object",
        "properties": {
          "traits": {
            "type": "object",
            "properties": {
              "uuid": {
                "type": "string",
                "title": "uuid"
              },
              "email": {
                "type": "string",
                "format": "email",
                "title": "E-Mail",
                "minLength": 3,
                "<http://ory.sh/kratos|ory.sh/kratos>": {
                  "recovery": {
                    "via": "email"
                  },
                  "credentials": {
                    "password": {
                      "identifier": true
                    },
                    "totp": {
                      "account_name": true
                    },
                    "webauthn": {
                      "identifier": true
                    }
                  }
                }
              },
              "username": {
                "type": "string",
                "<http://ory.sh/kratos|ory.sh/kratos>": {
                  "credentials": {
                    "password": {
                      "identifier": true
                    }
                  }
                }
              },
              "name": {
                "type": "string",
                "title": "Full name"
              }
            },
            "required": ["email"],
            "additionalProperties": false
          }
        }
      }
I'll dig up the row of two of the affected users -- do you want just the
identity_credentials
one? However, our non-technical admin already attempted to delete any webauthn entry they had via the kratos api, hoping to solve their login problem this way. I'm still waiting to hear back if that has solved their issue. But it could be the current state no longer relects the original problem.
Here's one user:
Copy code
select ic.* from identity_credentials ic join identities i on ic.identity_id = i.id where i.traits like "%[...]%" \G
*************************** 1. row ***************************
                         id: [...]
                     config: {"hashed_password":"[...]"}
identity_credential_type_id: [...]
                identity_id: [...]
                 created_at: 2025-03-20 14:07:47
                 updated_at: 2025-06-26 09:09:43
                        nid: [...]
                    version: 0
*************************** 2. row ***************************
                         id: [...]
                     config: {"user_handle":"[...]"}
identity_credential_type_id: [...]
                identity_id: [...]
                 created_at: 2025-06-23 08:58:16
                 updated_at: 2025-06-26 09:09:43
                        nid: [...]
                    version: 1
The entries for the other user are equivalent.
s
The identity should have an available aal field, what is that?
w
I don't see that field in the output of GETting
api/v1/users/[...]
, should I?
s
that's not a kratos api 🤔
w
Oh it's in the database.
Ah sorry that's our own api which talks to kratos in the backend.
It relays the kratos output though.
Both have
available_aal
of
aal1
-- at this time, though this is after deleting the webauthn 2FA via the api.
Is that field used by kratos to decide whether to ask for 2FA at login?
s
iirc yes, it is updated when the credentials change
an incorrect value there might have caused this
w
Okay thanks. If and when I have confirmed an ongoing problem with one of the users, I'll check that field (again). That should at least distinguish between kratos wrongly showing the 2fa form and some weird circumstance that makes that field unexpectedly be >
aal1
.
Is it okay if I tag you again later if/when I have more data?
s
yes, just let me know if we find that that is the problem, we'd have to dig deeper how that happens, so ideally you would have logs and other activity around that user available