package oidc import "github.com/zitadel/zitadel/internal/domain" const ( // Password states that the users password has been verified // Deprecated: use `PWD` instead Password = "password" // PWD states that the users password has been verified PWD = "pwd" // MFA states that multiple factors have been verified (e.g. pwd and otp or passkey) MFA = "mfa" // OTP states that a one time password has been verified (e.g. TOTP) OTP = "otp" // UserPresence states that the end users presence has been verified (e.g. passkey and u2f) UserPresence = "user" ) // AuthMethodTypesToAMR maps zitadel auth method types to Authentication Method Reference Values // as defined in [RFC 8176, section 2]. // // [RFC 8176, section 2]: https://datatracker.ietf.org/doc/html/rfc8176#section-2 func AuthMethodTypesToAMR(methodTypes []domain.UserAuthMethodType) []string { if methodTypes == nil { return nil // make sure amr is omitted when not provided / supported } amr := make([]string, 0, 4) var factors, otp int for _, methodType := range methodTypes { switch methodType { case domain.UserAuthMethodTypePassword: amr = append(amr, PWD) factors++ case domain.UserAuthMethodTypePasswordless: amr = append(amr, UserPresence) factors += 2 case domain.UserAuthMethodTypeU2F: amr = append(amr, UserPresence) factors++ case domain.UserAuthMethodTypeOTP, domain.UserAuthMethodTypeTOTP, domain.UserAuthMethodTypeOTPSMS, domain.UserAuthMethodTypeOTPEmail: // a user could use multiple (t)otp, which is a factor, but still will be returned as a single `otp` entry otp++ factors++ case domain.UserAuthMethodTypeIDP: // no AMR value according to specification factors++ case domain.UserAuthMethodTypeUnspecified: // ignore } } if otp > 0 { amr = append(amr, OTP) } if factors >= 2 { amr = append(amr, MFA) } return amr } func AMRToAuthMethodTypes(amr []string) []domain.UserAuthMethodType { authMethods := make([]domain.UserAuthMethodType, 0, len(amr)) var ( userPresence bool mfa bool ) for _, entry := range amr { switch entry { case Password, PWD: authMethods = append(authMethods, domain.UserAuthMethodTypePassword) case OTP: authMethods = append(authMethods, domain.UserAuthMethodTypeOTP) case UserPresence: userPresence = true case MFA: mfa = true } } if userPresence { if mfa { authMethods = append(authMethods, domain.UserAuthMethodTypePasswordless) } else { authMethods = append(authMethods, domain.UserAuthMethodTypeU2F) } } return authMethods }