Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-okta for openSUSE:Factory checked in at 2026-07-06 12:31:35 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-okta (Old) and /work/SRC/openSUSE:Factory/.python-okta.new.1982 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-okta" Mon Jul 6 12:31:35 2026 rev:9 rq:1363832 version:3.4.4 Changes: -------- --- /work/SRC/openSUSE:Factory/python-okta/python-okta.changes 2026-05-14 21:45:56.873975685 +0200 +++ /work/SRC/openSUSE:Factory/.python-okta.new.1982/python-okta.changes 2026-07-06 12:34:05.399056287 +0200 @@ -1,0 +2,18 @@ +Sun Jul 5 09:36:42 UTC 2026 - Dirk Müller <[email protected]> + +- update to 3.4.4: + * Fixed a `ValidationError` crash in `list_factors()` when + processing users enrolled in Okta FastPass. Added missing + `signed_nonce` discriminator mapping and three new component + schemas (`UserFactorSignedNonce`, + `UserFactorSignedNonceProfile`, + `UserFactorSignedNonceProfileKey`) to properly deserialize + FastPass factor payloads (#311, 387). + * Fixed enum case mismatches in `AccessPolicyConstraint`, + `KnowledgeConstraint`, and `PossessionConstraint` models. The + `methods` and `types` fields now correctly accept lowercase + values (e.g., `"password"`, `"push"`, `"webauthn"`) to align + with actual API responses, resolving `ValidationError` + exceptions raised by `list_policy_rules()` (#548). + +------------------------------------------------------------------- Old: ---- okta-sdk-python-3.4.3.tar.gz New: ---- okta-sdk-python-3.4.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-okta.spec ++++++ --- /var/tmp/diff_new_pack.11lAFH/_old 2026-07-06 12:34:06.563096729 +0200 +++ /var/tmp/diff_new_pack.11lAFH/_new 2026-07-06 12:34:06.563096729 +0200 @@ -19,7 +19,7 @@ %{?sle15_python_module_pythons} Name: python-okta -Version: 3.4.3 +Version: 3.4.4 Release: 0 Summary: Python SDK for the Okta Management API License: Apache-2.0 @@ -40,7 +40,7 @@ BuildRequires: %{python_module flatdict} BuildRequires: %{python_module jwcrypto} BuildRequires: %{python_module pycryptodomex} -BuildRequires: %{python_module pydantic} +BuildRequires: %{python_module pydantic >= 2} BuildRequires: %{python_module pydash} BuildRequires: %{python_module pytest-asyncio} BuildRequires: %{python_module pytest-mock} @@ -49,8 +49,10 @@ BuildRequires: %{python_module pytest-trio} BuildRequires: %{python_module pytest-twisted} BuildRequires: %{python_module pytest} -BuildRequires: %{python_module python-dateutil} +BuildRequires: %{python_module python-dateutil >= 2.8.2} BuildRequires: %{python_module requests} +BuildRequires: %{python_module typing-extensions >= 4.7.1} +BuildRequires: %{python_module urllib3 >= 1.25.3} BuildRequires: %{python_module xmltodict} BuildRequires: %{python_module yarl} # /SECTION @@ -63,10 +65,12 @@ Requires: python-flatdict Requires: python-jwcrypto Requires: python-pycryptodomex -Requires: python-pydantic +Requires: python-pydantic >= 2 Requires: python-pydash -Requires: python-python-dateutil +Requires: python-python-dateutil >= 2.8.2 Requires: python-requests +Requires: python-typing-extensions >= 4.7.1 +Requires: python-urllib3 >= 1.25.3 Requires: python-xmltodict Requires: python-yarl BuildArch: noarch ++++++ okta-sdk-python-3.4.3.tar.gz -> okta-sdk-python-3.4.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/CHANGELOG.md new/okta-sdk-python-3.4.4/CHANGELOG.md --- old/okta-sdk-python-3.4.3/CHANGELOG.md 2026-05-13 08:51:15.000000000 +0200 +++ new/okta-sdk-python-3.4.4/CHANGELOG.md 2026-07-01 10:32:35.000000000 +0200 @@ -1,5 +1,11 @@ # Okta Python SDK Changelog +# 3.4.4 + +## Fixed +* Fixed a `ValidationError` crash in `list_factors()` when processing users enrolled in Okta FastPass. Added missing `signed_nonce` discriminator mapping and three new component schemas (`UserFactorSignedNonce`, `UserFactorSignedNonceProfile`, `UserFactorSignedNonceProfileKey`) to properly deserialize FastPass factor payloads ([#311](https://github.com/okta/okta-sdk-python/issues/311), [387](https://github.com/okta/okta-sdk-python/issues/387)). +* Fixed enum case mismatches in `AccessPolicyConstraint`, `KnowledgeConstraint`, and `PossessionConstraint` models. The `methods` and `types` fields now correctly accept lowercase values (e.g., `"password"`, `"push"`, `"webauthn"`) to align with actual API responses, resolving `ValidationError` exceptions raised by `list_policy_rules()` ([#548](https://github.com/okta/okta-sdk-python/issues/548)). + # 3.4.3 ## Bug Fixes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/docs/UserFactorSignedNonce.md new/okta-sdk-python-3.4.4/docs/UserFactorSignedNonce.md --- old/okta-sdk-python-3.4.3/docs/UserFactorSignedNonce.md 1970-01-01 01:00:00.000000000 +0100 +++ new/okta-sdk-python-3.4.4/docs/UserFactorSignedNonce.md 2026-07-01 10:32:35.000000000 +0200 @@ -0,0 +1,32 @@ +# UserFactorSignedNonce + +`signed_nonce` is the factor type for [Okta FastPass](https://help.okta.com/oie/en-us/content/topics/identity-engine/devices/fp/fp-main.htm). You can't use the Factors API to enroll or activate Okta FastPass (`signed_nonce`) for a user. Use the [Okta Verify](https://help.okta.com/en-us/content/topics/mobile/okta-verify-overview.htm) authenticator enrollment flow instead. You can use the Factors API to list and delete `signed_nonce` factors. + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**factor_type** | **object** | | [optional] +**profile** | [**UserFactorSignedNonceProfile**](UserFactorSignedNonceProfile.md) | | [optional] +**provider** | **str** | | [optional] + +## Example + +```python +from okta.models.user_factor_signed_nonce import UserFactorSignedNonce + +# TODO update the JSON string below +json = "{}" +# create an instance of UserFactorSignedNonce from a JSON string +user_factor_signed_nonce_instance = UserFactorSignedNonce.from_json(json) +# print the JSON string representation of the object +print(UserFactorSignedNonce.to_json()) + +# convert the object into a dict +user_factor_signed_nonce_dict = user_factor_signed_nonce_instance.to_dict() +# create an instance of UserFactorSignedNonce from a dict +user_factor_signed_nonce_from_dict = UserFactorSignedNonce.from_dict(user_factor_signed_nonce_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/docs/UserFactorSignedNonceProfile.md new/okta-sdk-python-3.4.4/docs/UserFactorSignedNonceProfile.md --- old/okta-sdk-python-3.4.3/docs/UserFactorSignedNonceProfile.md 1970-01-01 01:00:00.000000000 +0100 +++ new/okta-sdk-python-3.4.4/docs/UserFactorSignedNonceProfile.md 2026-07-01 10:32:35.000000000 +0200 @@ -0,0 +1,35 @@ +# UserFactorSignedNonceProfile + +Profile for the Okta FastPass (signed nonce) factor + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**credential_id** | **str** | ID for the factor credential | [optional] +**device_type** | **str** | Type of device | [optional] +**name** | **str** | Name of the device | [optional] +**platform** | **str** | OS platform of the associated device | [optional] +**version** | **str** | OS version of the associated device | [optional] +**keys** | [**List[UserFactorSignedNonceProfileKey]**](UserFactorSignedNonceProfileKey.md) | Cryptographic keys associated with the signed nonce factor | [optional] + +## Example + +```python +from okta.models.user_factor_signed_nonce_profile import UserFactorSignedNonceProfile + +# TODO update the JSON string below +json = "{}" +# create an instance of UserFactorSignedNonceProfile from a JSON string +user_factor_signed_nonce_profile_instance = UserFactorSignedNonceProfile.from_json(json) +# print the JSON string representation of the object +print(UserFactorSignedNonceProfile.to_json()) + +# convert the object into a dict +user_factor_signed_nonce_profile_dict = user_factor_signed_nonce_profile_instance.to_dict() +# create an instance of UserFactorSignedNonceProfile from a dict +user_factor_signed_nonce_profile_from_dict = UserFactorSignedNonceProfile.from_dict(user_factor_signed_nonce_profile_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/docs/UserFactorSignedNonceProfileKey.md new/okta-sdk-python-3.4.4/docs/UserFactorSignedNonceProfileKey.md --- old/okta-sdk-python-3.4.3/docs/UserFactorSignedNonceProfileKey.md 1970-01-01 01:00:00.000000000 +0100 +++ new/okta-sdk-python-3.4.4/docs/UserFactorSignedNonceProfileKey.md 2026-07-01 10:32:35.000000000 +0200 @@ -0,0 +1,39 @@ +# UserFactorSignedNonceProfileKey + +JSON Web Key (JWK) for signed nonce verification + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**kty** | **str** | Key type | [optional] +**use** | **str** | Key usage | [optional] +**kid** | **str** | Key ID | [optional] +**jwk_type** | **str** | Purpose of the key | [optional] +**e** | **str** | RSA public exponent (present only for RSA keys) | [optional] +**n** | **str** | RSA modulus (present only for RSA keys) | [optional] +**crv** | **str** | EC curve name (present only for EC keys) | [optional] +**x** | **str** | EC x-coordinate (present only for EC keys) | [optional] +**y** | **str** | EC y-coordinate (present only for EC keys) | [optional] +**x5c** | **List[str]** | X.509 certificate chain | [optional] + +## Example + +```python +from okta.models.user_factor_signed_nonce_profile_key import UserFactorSignedNonceProfileKey + +# TODO update the JSON string below +json = "{}" +# create an instance of UserFactorSignedNonceProfileKey from a JSON string +user_factor_signed_nonce_profile_key_instance = UserFactorSignedNonceProfileKey.from_json(json) +# print the JSON string representation of the object +print(UserFactorSignedNonceProfileKey.to_json()) + +# convert the object into a dict +user_factor_signed_nonce_profile_key_dict = user_factor_signed_nonce_profile_key_instance.to_dict() +# create an instance of UserFactorSignedNonceProfileKey from a dict +user_factor_signed_nonce_profile_key_from_dict = UserFactorSignedNonceProfileKey.from_dict(user_factor_signed_nonce_profile_key_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/okta/__init__.py new/okta-sdk-python-3.4.4/okta/__init__.py --- old/okta-sdk-python-3.4.3/okta/__init__.py 2026-05-13 08:51:15.000000000 +0200 +++ new/okta-sdk-python-3.4.4/okta/__init__.py 2026-07-01 10:32:35.000000000 +0200 @@ -21,7 +21,7 @@ """ # noqa: E501 -__version__ = "3.4.3" +__version__ = "3.4.4" import importlib as _importlib import threading as _threading @@ -1803,6 +1803,9 @@ "UserFactorSMSProfile": "okta.models.user_factor_sms_profile", "UserFactorSecurityQuestion": "okta.models.user_factor_security_question", "UserFactorSecurityQuestionProfile": "okta.models.user_factor_security_question_profile", + "UserFactorSignedNonce": "okta.models.user_factor_signed_nonce", + "UserFactorSignedNonceProfile": "okta.models.user_factor_signed_nonce_profile", + "UserFactorSignedNonceProfileKey": "okta.models.user_factor_signed_nonce_profile_key", "UserFactorStatus": "okta.models.user_factor_status", "UserFactorSupported": "okta.models.user_factor_supported", "UserFactorToken": "okta.models.user_factor_token", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/okta/models/__init__.py new/okta-sdk-python-3.4.4/okta/models/__init__.py --- old/okta-sdk-python-3.4.3/okta/models/__init__.py 2026-05-13 08:51:15.000000000 +0200 +++ new/okta-sdk-python-3.4.4/okta/models/__init__.py 2026-07-01 10:32:35.000000000 +0200 @@ -232,6 +232,7 @@ 'UserFactorEmail', 'UserFactorPush', 'UserFactorSecurityQuestion', + 'UserFactorSignedNonce', 'UserFactorSMS', 'UserFactorToken', 'UserFactorTokenHardware', @@ -2004,6 +2005,9 @@ "UserFactorSMSProfile": "okta.models.user_factor_sms_profile", "UserFactorSecurityQuestion": "okta.models.user_factor_security_question", "UserFactorSecurityQuestionProfile": "okta.models.user_factor_security_question_profile", + "UserFactorSignedNonce": "okta.models.user_factor_signed_nonce", + "UserFactorSignedNonceProfile": "okta.models.user_factor_signed_nonce_profile", + "UserFactorSignedNonceProfileKey": "okta.models.user_factor_signed_nonce_profile_key", "UserFactorStatus": "okta.models.user_factor_status", "UserFactorSupported": "okta.models.user_factor_supported", "UserFactorToken": "okta.models.user_factor_token", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/okta/models/access_policy_constraint.py new/okta-sdk-python-3.4.4/okta/models/access_policy_constraint.py --- old/okta-sdk-python-3.4.3/okta/models/access_policy_constraint.py 2026-05-13 08:51:15.000000000 +0200 +++ new/okta-sdk-python-3.4.4/okta/models/access_policy_constraint.py 2026-07-01 10:32:35.000000000 +0200 @@ -99,24 +99,24 @@ for i in value: if i not in set( [ - "PASSWORD", - "SECURITY_QUESTION", - "SMS", - "VOICE", - "EMAIL", - "PUSH", - "SIGNED_NONCE", - "OTP", - "TOTP", - "WEBAUTHN", - "DUO", - "IDP", - "CERT", + "password", + "security_question", + "sms", + "voice", + "email", + "push", + "signed_nonce", + "otp", + "totp", + "webauthn", + "duo", + "idp", + "cert", ] ): raise ValueError( - "each list item must be one of ('PASSWORD', 'SECURITY_QUESTION', 'SMS', 'VOICE', 'EMAIL', 'PUSH', " - "'SIGNED_NONCE', 'OTP', 'TOTP', 'WEBAUTHN', 'DUO', 'IDP', 'CERT')" + "each list item must be one of ('password', 'security_question', 'sms', 'voice', 'email', 'push', " + "'signed_nonce', 'otp', 'totp', 'webauthn', 'duo', 'idp', 'cert')" ) return value @@ -129,18 +129,18 @@ for i in value: if i not in set( [ - "SECURITY_KEY", - "PHONE", - "EMAIL", - "PASSWORD", - "SECURITY_QUESTION", - "APP", - "FEDERATED", + "security_key", + "phone", + "email", + "password", + "security_question", + "app", + "federated", ] ): raise ValueError( - "each list item must be one of ('SECURITY_KEY', 'PHONE', 'EMAIL', 'PASSWORD', 'SECURITY_QUESTION', " - "'APP', 'FEDERATED')" + "each list item must be one of ('security_key', 'phone', 'email', 'password', 'security_question', " + "'app', 'federated')" ) return value diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/okta/models/knowledge_constraint.py new/okta-sdk-python-3.4.4/okta/models/knowledge_constraint.py --- old/okta-sdk-python-3.4.3/okta/models/knowledge_constraint.py 2026-05-13 08:51:15.000000000 +0200 +++ new/okta-sdk-python-3.4.4/okta/models/knowledge_constraint.py 2026-07-01 10:32:35.000000000 +0200 @@ -96,24 +96,24 @@ for i in value: if i not in set( [ - "PASSWORD", - "SECURITY_QUESTION", - "SMS", - "VOICE", - "EMAIL", - "PUSH", - "SIGNED_NONCE", - "OTP", - "TOTP", - "WEBAUTHN", - "DUO", - "IDP", - "CERT", + "password", + "security_question", + "sms", + "voice", + "email", + "push", + "signed_nonce", + "otp", + "totp", + "webauthn", + "duo", + "idp", + "cert", ] ): raise ValueError( - "each list item must be one of ('PASSWORD', 'SECURITY_QUESTION', 'SMS', 'VOICE', 'EMAIL', 'PUSH', " - "'SIGNED_NONCE', 'OTP', 'TOTP', 'WEBAUTHN', 'DUO', 'IDP', 'CERT')" + "each list item must be one of ('password', 'security_question', 'sms', 'voice', 'email', 'push', " + "'signed_nonce', 'otp', 'totp', 'webauthn', 'duo', 'idp', 'cert')" ) return value @@ -126,18 +126,18 @@ for i in value: if i not in set( [ - "SECURITY_KEY", - "PHONE", - "EMAIL", - "PASSWORD", - "SECURITY_QUESTION", - "APP", - "FEDERATED", + "security_key", + "phone", + "email", + "password", + "security_question", + "app", + "federated", ] ): raise ValueError( - "each list item must be one of ('SECURITY_KEY', 'PHONE', 'EMAIL', 'PASSWORD', 'SECURITY_QUESTION', " - "'APP', 'FEDERATED')" + "each list item must be one of ('security_key', 'phone', 'email', 'password', 'security_question', " + "'app', 'federated')" ) return value diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/okta/models/possession_constraint.py new/okta-sdk-python-3.4.4/okta/models/possession_constraint.py --- old/okta-sdk-python-3.4.3/okta/models/possession_constraint.py 2026-05-13 08:51:15.000000000 +0200 +++ new/okta-sdk-python-3.4.4/okta/models/possession_constraint.py 2026-07-01 10:32:35.000000000 +0200 @@ -137,24 +137,24 @@ for i in value: if i not in set( [ - "PASSWORD", - "SECURITY_QUESTION", - "SMS", - "VOICE", - "EMAIL", - "PUSH", - "SIGNED_NONCE", - "OTP", - "TOTP", - "WEBAUTHN", - "DUO", - "IDP", - "CERT", + "password", + "security_question", + "sms", + "voice", + "email", + "push", + "signed_nonce", + "otp", + "totp", + "webauthn", + "duo", + "idp", + "cert", ] ): raise ValueError( - "each list item must be one of ('PASSWORD', 'SECURITY_QUESTION', 'SMS', 'VOICE', 'EMAIL', 'PUSH', " - "'SIGNED_NONCE', 'OTP', 'TOTP', 'WEBAUTHN', 'DUO', 'IDP', 'CERT')" + "each list item must be one of ('password', 'security_question', 'sms', 'voice', 'email', 'push', " + "'signed_nonce', 'otp', 'totp', 'webauthn', 'duo', 'idp', 'cert')" ) return value @@ -167,18 +167,18 @@ for i in value: if i not in set( [ - "SECURITY_KEY", - "PHONE", - "EMAIL", - "PASSWORD", - "SECURITY_QUESTION", - "APP", - "FEDERATED", + "security_key", + "phone", + "email", + "password", + "security_question", + "app", + "federated", ] ): raise ValueError( - "each list item must be one of ('SECURITY_KEY', 'PHONE', 'EMAIL', 'PASSWORD', 'SECURITY_QUESTION', " - "'APP', 'FEDERATED')" + "each list item must be one of ('security_key', 'phone', 'email', 'password', 'security_question', " + "'app', 'federated')" ) return value diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/okta/models/user_factor.py new/okta-sdk-python-3.4.4/okta/models/user_factor.py --- old/okta-sdk-python-3.4.3/okta/models/user_factor.py 2026-05-13 08:51:15.000000000 +0200 +++ new/okta-sdk-python-3.4.4/okta/models/user_factor.py 2026-07-01 10:32:35.000000000 +0200 @@ -42,6 +42,7 @@ from okta.models.user_factor_email import UserFactorEmail from okta.models.user_factor_push import UserFactorPush from okta.models.user_factor_security_question import UserFactorSecurityQuestion + from okta.models.user_factor_signed_nonce import UserFactorSignedNonce from okta.models.user_factor_sms import UserFactorSMS from okta.models.user_factor_token import UserFactorToken from okta.models.user_factor_token_hardware import UserFactorTokenHardware @@ -113,6 +114,7 @@ "email": "UserFactorEmail", "push": "UserFactorPush", "question": "UserFactorSecurityQuestion", + "signed_nonce": "UserFactorSignedNonce", "sms": "UserFactorSMS", "token": "UserFactorToken", "token:hardware": "UserFactorTokenHardware", @@ -148,6 +150,7 @@ UserFactorEmail, UserFactorPush, UserFactorSecurityQuestion, + UserFactorSignedNonce, UserFactorSMS, UserFactorToken, UserFactorTokenHardware, @@ -207,6 +210,7 @@ UserFactorEmail, UserFactorPush, UserFactorSecurityQuestion, + UserFactorSignedNonce, UserFactorSMS, UserFactorToken, UserFactorTokenHardware, @@ -242,6 +246,11 @@ if object_type == cls.__name__: return cls.model_validate(obj) return models.UserFactorSecurityQuestion.from_dict(obj) + if object_type == "UserFactorSignedNonce": + # Check if the discriminator maps to the same class to avoid infinite recursion + if object_type == cls.__name__: + return cls.model_validate(obj) + return models.UserFactorSignedNonce.from_dict(obj) if object_type == "UserFactorSMS": # Check if the discriminator maps to the same class to avoid infinite recursion if object_type == cls.__name__: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/okta/models/user_factor_signed_nonce.py new/okta-sdk-python-3.4.4/okta/models/user_factor_signed_nonce.py --- old/okta-sdk-python-3.4.3/okta/models/user_factor_signed_nonce.py 1970-01-01 01:00:00.000000000 +0100 +++ new/okta-sdk-python-3.4.4/okta/models/user_factor_signed_nonce.py 2026-07-01 10:32:35.000000000 +0200 @@ -0,0 +1,163 @@ +# The Okta software accompanied by this notice is provided pursuant to the following terms: +# Copyright © 2025-Present, Okta, Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the +# License. +# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. +# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS +# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and limitations under the License. +# coding: utf-8 + +""" +Okta Admin Management + +Allows customers to easily access the Okta Management APIs + +The version of the OpenAPI document: 5.1.0 +Contact: [email protected] +Generated by OpenAPI Generator (https://openapi-generator.tech) + +Do not edit the class manually. +""" # noqa: E501 + +from __future__ import annotations + +import json +import pprint +import re # noqa: F401 +from typing import Any, ClassVar, Dict, List +from typing import Optional, Set + +from pydantic import ConfigDict, Field, StrictStr, field_validator +from typing_extensions import Self + +from okta.models.user_factor import UserFactor +from okta.models.user_factor_links import UserFactorLinks +from okta.models.user_factor_signed_nonce_profile import UserFactorSignedNonceProfile + + +class UserFactorSignedNonce(UserFactor): + """ + `signed_nonce` is the factor type for [Okta FastPass]( + https://help.okta.com/oie/en-us/content/topics/identity-engine/devices/fp/fp-main.htm). You can't use the Factors API to + enroll or activate Okta FastPass (`signed_nonce`) for a user. Use the [Okta Verify]( + https://help.okta.com/en-us/content/topics/mobile/okta-verify-overview.htm) authenticator enrollment flow instead. You + can use the Factors API to list and delete `signed_nonce` factors. + """ # noqa: E501 + + factor_type: Optional[Any] = Field(default=None, alias="factorType") + profile: Optional[UserFactorSignedNonceProfile] = None + provider: Optional[StrictStr] = None + __properties: ClassVar[List[str]] = [ + "created", + "factorType", + "id", + "lastUpdated", + "profile", + "provider", + "status", + "vendorName", + "_embedded", + "_links", + ] + + @field_validator("provider") + def provider_validate_enum(cls, value): + """Validates the enum""" + if value is None: + return value + + if value not in set(["OKTA"]): + raise ValueError("must be one of enum values ('OKTA')") + return value + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of UserFactorSignedNonce from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # override the default output from pydantic by calling `to_dict()` of profile + if self.profile: + if not isinstance(self.profile, dict): + _dict["profile"] = self.profile.to_dict() + else: + _dict["profile"] = self.profile + + # override the default output from pydantic by calling `to_dict()` of links + if self.links: + if not isinstance(self.links, dict): + _dict["_links"] = self.links.to_dict() + else: + _dict["_links"] = self.links + + # set to None if factor_type (nullable) is None + # and model_fields_set contains the field + if self.factor_type is None and "factor_type" in self.model_fields_set: + _dict["factorType"] = None + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of UserFactorSignedNonce from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + { + "created": obj.get("created"), + "factorType": obj.get("factorType"), + "id": obj.get("id"), + "lastUpdated": obj.get("lastUpdated"), + "profile": ( + UserFactorSignedNonceProfile.from_dict(obj["profile"]) + if obj.get("profile") is not None + else None + ), + "provider": obj.get("provider"), + "status": obj.get("status"), + "vendorName": obj.get("vendorName"), + "_embedded": obj.get("_embedded"), + "_links": ( + UserFactorLinks.from_dict(obj["_links"]) + if obj.get("_links") is not None + else None + ), + } + ) + return _obj diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/okta/models/user_factor_signed_nonce_profile.py new/okta-sdk-python-3.4.4/okta/models/user_factor_signed_nonce_profile.py --- old/okta-sdk-python-3.4.3/okta/models/user_factor_signed_nonce_profile.py 1970-01-01 01:00:00.000000000 +0100 +++ new/okta-sdk-python-3.4.4/okta/models/user_factor_signed_nonce_profile.py 2026-07-01 10:32:35.000000000 +0200 @@ -0,0 +1,142 @@ +# The Okta software accompanied by this notice is provided pursuant to the following terms: +# Copyright © 2025-Present, Okta, Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the +# License. +# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. +# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS +# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and limitations under the License. +# coding: utf-8 + +""" +Okta Admin Management + +Allows customers to easily access the Okta Management APIs + +The version of the OpenAPI document: 5.1.0 +Contact: [email protected] +Generated by OpenAPI Generator (https://openapi-generator.tech) + +Do not edit the class manually. +""" # noqa: E501 + +from __future__ import annotations + +import json +import pprint +import re # noqa: F401 +from typing import Any, ClassVar, Dict, List +from typing import Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing_extensions import Self + +from okta.models.user_factor_signed_nonce_profile_key import ( + UserFactorSignedNonceProfileKey, +) + + +class UserFactorSignedNonceProfile(BaseModel): + """ + Profile for the Okta FastPass (signed nonce) factor + """ # noqa: E501 + + credential_id: Optional[StrictStr] = Field( + default=None, description="ID for the factor credential", alias="credentialId" + ) + device_type: Optional[StrictStr] = Field( + default=None, description="Type of device", alias="deviceType" + ) + name: Optional[StrictStr] = Field(default=None, description="Name of the device") + platform: Optional[StrictStr] = Field( + default=None, description="OS platform of the associated device" + ) + version: Optional[StrictStr] = Field( + default=None, description="OS version of the associated device" + ) + keys: Optional[List[UserFactorSignedNonceProfileKey]] = Field( + default=None, + description="Cryptographic keys associated with the signed nonce factor", + ) + __properties: ClassVar[List[str]] = [ + "credentialId", + "deviceType", + "name", + "platform", + "version", + "keys", + ] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of UserFactorSignedNonceProfile from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # override the default output from pydantic by calling `to_dict()` of each item in keys (list) + _items = [] + if self.keys: + for _item in self.keys: + if _item: + _items.append(_item.to_dict()) + _dict["keys"] = _items + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of UserFactorSignedNonceProfile from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + { + "credentialId": obj.get("credentialId"), + "deviceType": obj.get("deviceType"), + "name": obj.get("name"), + "platform": obj.get("platform"), + "version": obj.get("version"), + "keys": ( + [ + UserFactorSignedNonceProfileKey.from_dict(_item) + for _item in obj["keys"] + ] + if obj.get("keys") is not None + else None + ), + } + ) + return _obj diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/okta/models/user_factor_signed_nonce_profile_key.py new/okta-sdk-python-3.4.4/okta/models/user_factor_signed_nonce_profile_key.py --- old/okta-sdk-python-3.4.3/okta/models/user_factor_signed_nonce_profile_key.py 1970-01-01 01:00:00.000000000 +0100 +++ new/okta-sdk-python-3.4.4/okta/models/user_factor_signed_nonce_profile_key.py 2026-07-01 10:32:35.000000000 +0200 @@ -0,0 +1,163 @@ +# The Okta software accompanied by this notice is provided pursuant to the following terms: +# Copyright © 2025-Present, Okta, Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the +# License. +# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. +# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS +# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and limitations under the License. +# coding: utf-8 + +""" +Okta Admin Management + +Allows customers to easily access the Okta Management APIs + +The version of the OpenAPI document: 5.1.0 +Contact: [email protected] +Generated by OpenAPI Generator (https://openapi-generator.tech) + +Do not edit the class manually. +""" # noqa: E501 + +from __future__ import annotations + +import json +import pprint +import re # noqa: F401 +from typing import Any, ClassVar, Dict, List +from typing import Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator +from typing_extensions import Self + + +class UserFactorSignedNonceProfileKey(BaseModel): + """ + JSON Web Key (JWK) for signed nonce verification + """ # noqa: E501 + + kty: Optional[StrictStr] = Field(default=None, description="Key type") + use: Optional[StrictStr] = Field(default=None, description="Key usage") + kid: Optional[StrictStr] = Field(default=None, description="Key ID") + jwk_type: Optional[StrictStr] = Field( + default=None, description="Purpose of the key", alias="jwkType" + ) + e: Optional[StrictStr] = Field( + default=None, description="RSA public exponent (present only for RSA keys)" + ) + n: Optional[StrictStr] = Field( + default=None, description="RSA modulus (present only for RSA keys)" + ) + crv: Optional[StrictStr] = Field( + default=None, description="EC curve name (present only for EC keys)" + ) + x: Optional[StrictStr] = Field( + default=None, description="EC x-coordinate (present only for EC keys)" + ) + y: Optional[StrictStr] = Field( + default=None, description="EC y-coordinate (present only for EC keys)" + ) + x5c: Optional[List[StrictStr]] = Field( + default=None, description="X.509 certificate chain" + ) + __properties: ClassVar[List[str]] = [ + "kty", + "use", + "kid", + "jwkType", + "e", + "n", + "crv", + "x", + "y", + "x5c", + ] + + @field_validator("kty") + def kty_validate_enum(cls, value): + """Validates the enum""" + if value is None: + return value + + if value not in set(["RSA", "EC"]): + raise ValueError("must be one of enum values ('RSA', 'EC')") + return value + + @field_validator("jwk_type") + def jwk_type_validate_enum(cls, value): + """Validates the enum""" + if value is None: + return value + + if value not in set( + ["proofOfPossession", "userVerification", "userVerificationBioOrPin"] + ): + raise ValueError( + "must be one of enum values ('proofOfPossession', 'userVerification', 'userVerificationBioOrPin')" + ) + return value + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of UserFactorSignedNonceProfileKey from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of UserFactorSignedNonceProfileKey from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + { + "kty": obj.get("kty"), + "use": obj.get("use"), + "kid": obj.get("kid"), + "jwkType": obj.get("jwkType"), + "e": obj.get("e"), + "n": obj.get("n"), + "crv": obj.get("crv"), + "x": obj.get("x"), + "y": obj.get("y"), + "x5c": obj.get("x5c"), + } + ) + return _obj diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/openapi/api.yaml new/okta-sdk-python-3.4.4/openapi/api.yaml --- old/okta-sdk-python-3.4.3/openapi/api.yaml 2026-05-13 08:51:15.000000000 +0200 +++ new/okta-sdk-python-3.4.4/openapi/api.yaml 2026-07-01 10:32:35.000000000 +0200 @@ -57789,19 +57789,19 @@ items: type: string enum: - - PASSWORD - - SECURITY_QUESTION - - SMS - - VOICE - - EMAIL - - PUSH - - SIGNED_NONCE - - OTP - - TOTP - - WEBAUTHN - - DUO - - IDP - - CERT + - password + - security_question + - sms + - voice + - email + - push + - signed_nonce + - otp + - totp + - webauthn + - duo + - idp + - cert type: array reauthenticateIn: description: The duration after which the user must re-authenticate regardless of user activity. This re-authentication interval overrides the Verification Method object's `reauthenticateIn` interval. The supported values use ISO 8601 period format for recurring time intervals (for example, `PT1H`). @@ -57814,13 +57814,13 @@ items: type: string enum: - - SECURITY_KEY - - PHONE - - EMAIL - - PASSWORD - - SECURITY_QUESTION - - APP - - FEDERATED + - security_key + - phone + - email + - password + - security_question + - app + - federated type: array AccessPolicyConstraints: description: Specifies constraints for the authenticator. Constraints are logically evaluated such that only one constraint object needs to be satisfied. But, within a constraint object, each constraint property must be satisfied. @@ -81003,6 +81003,7 @@ email: '#/components/schemas/UserFactorEmail' push: '#/components/schemas/UserFactorPush' question: '#/components/schemas/UserFactorSecurityQuestion' + signed_nonce: '#/components/schemas/UserFactorSignedNonce' sms: '#/components/schemas/UserFactorSMS' token: '#/components/schemas/UserFactorToken' token:hardware: '#/components/schemas/UserFactorTokenHardware' @@ -81771,6 +81772,99 @@ description: ID for the factor credential example: [email protected] type: string + UserFactorSignedNonce: + title: signed_nonce + description: |- + `signed_nonce` is the factor type for [Okta FastPass](https://help.okta.com/oie/en-us/content/topics/identity-engine/devices/fp/fp-main.htm). You can't use the Factors API to enroll or activate Okta FastPass (`signed_nonce`) for a user. Use the [Okta Verify](https://help.okta.com/en-us/content/topics/mobile/okta-verify-overview.htm) authenticator enrollment flow instead. + + You can use the Factors API to list and delete `signed_nonce` factors. + allOf: + - $ref: '#/components/schemas/UserFactor' + - type: object + properties: + factorType: + example: signed_nonce + profile: + $ref: '#/components/schemas/UserFactorSignedNonceProfile' + provider: + enum: + - OKTA + UserFactorSignedNonceProfile: + description: Profile for the Okta FastPass (signed nonce) factor + type: object + readOnly: true + properties: + credentialId: + description: ID for the factor credential + example: [email protected] + type: string + deviceType: + description: Type of device + example: SmartPhone_IPhone + type: string + name: + description: Name of the device + example: My Phone + type: string + platform: + description: OS platform of the associated device + example: IOS + type: string + version: + description: OS version of the associated device + example: '17.2' + type: string + keys: + description: Cryptographic keys associated with the signed nonce factor + type: array + items: + $ref: '#/components/schemas/UserFactorSignedNonceProfileKey' + UserFactorSignedNonceProfileKey: + description: JSON Web Key (JWK) for signed nonce verification + type: object + properties: + kty: + description: Key type + type: string + enum: + - RSA + - EC + use: + description: Key usage + type: string + example: sig + kid: + description: Key ID + type: string + example: default + jwkType: + description: Purpose of the key + type: string + enum: + - proofOfPossession + - userVerification + - userVerificationBioOrPin + e: + description: RSA public exponent (present only for RSA keys) + type: string + n: + description: RSA modulus (present only for RSA keys) + type: string + crv: + description: EC curve name (present only for EC keys) + type: string + example: P-256 + x: + description: EC x-coordinate (present only for EC keys) + type: string + y: + description: EC y-coordinate (present only for EC keys) + type: string + x5c: + description: X.509 certificate chain + type: array + items: + type: string UserFactorYubikeyOtpToken: type: object properties: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/openapi/config.yaml new/okta-sdk-python-3.4.4/openapi/config.yaml --- old/okta-sdk-python-3.4.3/openapi/config.yaml 2026-05-13 08:51:15.000000000 +0200 +++ new/okta-sdk-python-3.4.4/openapi/config.yaml 2026-07-01 10:32:35.000000000 +0200 @@ -1,7 +1,7 @@ templateDir: ./templates outputDir: .. packageName: okta -packageVersion: 3.4.3 +packageVersion: 3.4.4 useOneOfDiscriminatorLookup: true files: okta/okta_configuration.mustache: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/openapi/templates/setup.mustache new/okta-sdk-python-3.4.4/openapi/templates/setup.mustache --- old/okta-sdk-python-3.4.3/openapi/templates/setup.mustache 2026-05-13 08:51:15.000000000 +0200 +++ new/okta-sdk-python-3.4.4/openapi/templates/setup.mustache 2026-07-01 10:32:35.000000000 +0200 @@ -70,7 +70,7 @@ "Topic :: Software Development :: Libraries :: Python Modules", ], name=NAME, - version="3.4.3", + version="3.4.4", description="Python SDK for the Okta Management API", author="Okta, Inc.", author_email="[email protected]", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/pyproject.toml new/okta-sdk-python-3.4.4/pyproject.toml --- old/okta-sdk-python-3.4.3/pyproject.toml 2026-05-13 08:51:15.000000000 +0200 +++ new/okta-sdk-python-3.4.4/pyproject.toml 2026-07-01 10:32:35.000000000 +0200 @@ -1,6 +1,6 @@ [tool.poetry] name = "okta" -version = "3.4.3" +version = "3.4.4" description = "Okta Admin Management" authors = ["Okta Developer Team <[email protected]>"] license = "Apache-2.0" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/setup.py new/okta-sdk-python-3.4.4/setup.py --- old/okta-sdk-python-3.4.3/setup.py 2026-05-13 08:51:15.000000000 +0200 +++ new/okta-sdk-python-3.4.4/setup.py 2026-07-01 10:32:35.000000000 +0200 @@ -70,7 +70,7 @@ "Topic :: Software Development :: Libraries :: Python Modules", ], name=NAME, - version="3.4.3", + version="3.4.4", description="Python SDK for the Okta Management API", author="Okta, Inc.", author_email="[email protected]", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/tests/integration/cassettes/test_factors_it/TestFactorsResource.test_list_factors_signed_nonce.yaml new/okta-sdk-python-3.4.4/tests/integration/cassettes/test_factors_it/TestFactorsResource.test_list_factors_signed_nonce.yaml --- old/okta-sdk-python-3.4.3/tests/integration/cassettes/test_factors_it/TestFactorsResource.test_list_factors_signed_nonce.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/okta-sdk-python-3.4.4/tests/integration/cassettes/test_factors_it/TestFactorsResource.test_list_factors_signed_nonce.yaml 2026-07-01 10:32:35.000000000 +0200 @@ -0,0 +1,100 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Authorization: + - SSWS myAPIToken + User-Agent: + - OpenAPI-Generator/1.0.0/python + method: GET + uri: https://test.okta.com/api/v1/users + response: + body: + string: '[{"id":"00uFAKEFASTPASS000001","status":"ACTIVE","created":"2025-01-01T00:00:00.000Z","activated":null,"statusChanged":"2025-01-01T00:00:00.000Z","lastLogin":"2025-01-01T00:00:00.000Z","lastUpdated":"2025-01-01T00:00:00.000Z","passwordChanged":"2025-01-01T00:00:00.000Z","type":{"id":"otyFAKEUSERTYPE000001"},"profile":{"firstName":"Jane","lastName":"Doe-Signed-Nonce","mobilePhone":null,"secondEmail":null,"login":"[email protected]","email":"[email protected]"},"credentials":{"password":{},"emails":[{"value":"[email protected]","status":"VERIFIED","type":"PRIMARY"}],"provider":{"type":"OKTA","name":"OKTA"}},"_links":{"self":{"href":"https://test.okta.com/api/v1/users/00uFAKEFASTPASS000001"}}}]' + headers: + Cache-Control: + - no-cache, no-store + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Tue, 09 Jun 2026 06:04:03 GMT + Expires: + - '0' + Link: + - <https://test.okta.com/api/v1/users?limit=200>; rel="self" + Pragma: + - no-cache + Server: + - nginx + Strict-Transport-Security: + - max-age=315360000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-rate-limit-limit: + - '50' + x-rate-limit-remaining: + - '49' + x-rate-limit-reset: + - '1780985103' + x-xss-protection: + - '0' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Authorization: + - SSWS myAPIToken + User-Agent: + - OpenAPI-Generator/1.0.0/python + method: GET + uri: https://test.okta.com/api/v1/users/00uFAKEFASTPASS000001/factors + response: + body: + string: '[{"id":"crpFAKESIGNEDNONCE0001","factorType":"signed_nonce","provider":"OKTA","vendorName":"OKTA","status":"ACTIVE","created":"2025-01-01T00:00:00.000Z","lastUpdated":"2025-01-01T00:00:00.000Z","profile":{"credentialId":"[email protected]","deviceType":"SmartPhone_IPhone","name":"FAKEDEVICE01","platform":"IOS","version":"18.0.0","keys":[{"kty":"EC","use":"sig","kid":"default","jwkType":"proofOfPossession","x":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","y":"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB","crv":"P-256"},{"kty":"EC","use":"sig","kid":"default","jwkType":"userVerification","x":"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC","y":"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD","crv":"P-256"},{"kty":"EC","use":"sig","kid":"default","jwkType":"userVerificationBioOrPin","x":"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE","y":"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF","crv":"P-256"}]},"_links":{"self":{"href":"https://test.okta.com/api/v1/users/00u FAKEFASTPASS000001/factors/crpFAKESIGNEDNONCE0001","hints":{"allow":["GET","DELETE"]}},"user":{"href":"https://test.okta.com/api/v1/users/00uFAKEFASTPASS000001","hints":{"allow":["GET"]}}}},{"id":"ostFAKETOTP000000001","factorType":"token:software:totp","provider":"OKTA","vendorName":"OKTA","status":"ACTIVE","created":"2025-01-01T00:00:00.000Z","lastUpdated":"2025-01-01T00:00:00.000Z","profile":{"credentialId":"[email protected]"},"_links":{"self":{"href":"https://test.okta.com/api/v1/users/00uFAKEFASTPASS000001/factors/ostFAKETOTP000000001","hints":{"allow":["GET","DELETE"]}},"verify":{"href":"https://test.okta.com/api/v1/users/00uFAKEFASTPASS000001/factors/ostFAKETOTP000000001/verify","hints":{"allow":["POST"]}},"user":{"href":"https://test.okta.com/api/v1/users/00uFAKEFASTPASS000001","hints":{"allow":["GET"]}}}}]' + headers: + Cache-Control: + - no-cache, no-store + Connection: + - keep-alive + Content-Type: + - application/json + Date: + - Tue, 09 Jun 2026 06:04:04 GMT + Expires: + - '0' + Pragma: + - no-cache + Server: + - nginx + Strict-Transport-Security: + - max-age=315360000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-rate-limit-limit: + - '50' + x-rate-limit-remaining: + - '48' + x-rate-limit-reset: + - '1780985103' + x-xss-protection: + - '0' + status: + code: 200 + message: OK +version: 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/tests/integration/test_factors_it.py new/okta-sdk-python-3.4.4/tests/integration/test_factors_it.py --- old/okta-sdk-python-3.4.3/tests/integration/test_factors_it.py 2026-05-13 08:51:15.000000000 +0200 +++ new/okta-sdk-python-3.4.4/tests/integration/test_factors_it.py 2026-07-01 10:32:35.000000000 +0200 @@ -219,6 +219,69 @@ errors.append(exc) assert len(errors) == 0 + @pytest.mark.vcr() + @pytest.mark.asyncio + async def test_list_factors_signed_nonce(self, fs): + """ + Regression test for OKTA-1152856. + + Verifies that `list_factors()` correctly deserializes the Okta + FastPass `signed_nonce` factor type into a `UserFactorSignedNonce` + instance (with a populated `UserFactorSignedNonceProfile`) instead + of raising a Pydantic discriminator ValidationError. + + Note: `signed_nonce` cannot be enrolled via the Factors API (it is + provisioned through the Okta Verify authenticator enrollment + flow). This test therefore relies on a pre-existing FastPass- + enrolled user in the test org; it discovers that user by + iterating `list_users()` and inspecting each user's factors. + """ + # Instantiate Mock Client + client = MockOktaClient(fs) + + users, _, err = await client.list_users() + assert err is None + assert users is not None and len(users) > 0 + + signed_nonce_user = None + signed_nonce_factor = None + for user in users: + factors, _, factors_err = await client.list_factors(user.id) + assert factors_err is None + if not factors: + continue + for factor in factors: + if isinstance(factor, models.UserFactorSignedNonce): + signed_nonce_user = user + signed_nonce_factor = factor + break + if signed_nonce_factor is not None: + break + + assert signed_nonce_user is not None, ( + "No user enrolled with the signed_nonce (Okta FastPass) factor was " + "found in the test org. Enroll Okta Verify for a test user before " + "re-recording this cassette." + ) + + # Discriminator routed to the correct subclass + assert isinstance(signed_nonce_factor, models.UserFactorSignedNonce) + assert signed_nonce_factor.factor_type == models.UserFactorType.SIGNED_NONCE + assert signed_nonce_factor.provider == "OKTA" + assert signed_nonce_factor.id is not None + + # Nested profile deserialized into the new generated model + assert signed_nonce_factor.profile is not None + assert isinstance( + signed_nonce_factor.profile, models.UserFactorSignedNonceProfile + ) + + # If the profile carries JWK key material, ensure each key entry + # is also routed to the dedicated profile-key model. + if signed_nonce_factor.profile.keys: + for key in signed_nonce_factor.profile.keys: + assert isinstance(key, models.UserFactorSignedNonceProfileKey) + @pytest.mark.skip(reason="SDK bug: user_factor_links.py from_dict expects dict but API returns list for resend field") @pytest.mark.vcr() @pytest.mark.asyncio diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-sdk-python-3.4.3/tests/test_access_policy_constraint_enums.py new/okta-sdk-python-3.4.4/tests/test_access_policy_constraint_enums.py --- old/okta-sdk-python-3.4.3/tests/test_access_policy_constraint_enums.py 1970-01-01 01:00:00.000000000 +0100 +++ new/okta-sdk-python-3.4.4/tests/test_access_policy_constraint_enums.py 2026-07-01 10:32:35.000000000 +0200 @@ -0,0 +1,126 @@ +# The Okta software accompanied by this notice is provided pursuant to the following terms: +# Copyright © 2025-Present, Okta, Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the +# License. +# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. +# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and limitations under the License. +# coding: utf-8 + +""" +Unit tests verifying that `methods` and `types` enum validators on +`AccessPolicyConstraint`, `KnowledgeConstraint`, and `PossessionConstraint` +accept lowercase values (matching the live Okta API response casing) and +reject UPPERCASE / invalid values. + +Related: Alignment of OAS3 enum casing with the API. +""" + +import pytest +from pydantic import ValidationError + +from okta.models.access_policy_constraint import AccessPolicyConstraint +from okta.models.knowledge_constraint import KnowledgeConstraint +from okta.models.possession_constraint import PossessionConstraint + + +VALID_METHODS = [ + "password", "security_question", "sms", "voice", "email", + "push", "signed_nonce", "otp", "totp", "webauthn", "duo", "idp", "cert", +] +VALID_TYPES = [ + "security_key", "phone", "email", "password", + "security_question", "app", "federated", +] + + +class TestAccessPolicyConstraintEnums: + """Validator tests for the base `AccessPolicyConstraint` model.""" + + def test_lowercase_methods_accepted(self): + obj = AccessPolicyConstraint(methods=["password", "push", "webauthn"]) + assert obj.methods == ["password", "push", "webauthn"] + + def test_lowercase_types_accepted(self): + obj = AccessPolicyConstraint(types=["password", "security_key", "phone"]) + assert obj.types == ["password", "security_key", "phone"] + + def test_all_valid_methods_accepted(self): + obj = AccessPolicyConstraint(methods=list(VALID_METHODS)) + assert obj.methods == VALID_METHODS + + def test_all_valid_types_accepted(self): + obj = AccessPolicyConstraint(types=list(VALID_TYPES)) + assert obj.types == VALID_TYPES + + def test_uppercase_methods_rejected(self): + with pytest.raises(ValidationError): + AccessPolicyConstraint(methods=["PASSWORD"]) + + def test_uppercase_types_rejected(self): + with pytest.raises(ValidationError): + AccessPolicyConstraint(types=["PASSWORD"]) + + def test_unknown_method_rejected(self): + with pytest.raises(ValidationError): + AccessPolicyConstraint(methods=["not_a_real_method"]) + + def test_unknown_type_rejected(self): + with pytest.raises(ValidationError): + AccessPolicyConstraint(types=["not_a_real_type"]) + + def test_from_dict_lowercase_payload(self): + """Simulates a real API response payload.""" + payload = { + "methods": ["password", "push"], + "types": ["password"], + "required": True, + "reauthenticateIn": "PT2H", + } + obj = AccessPolicyConstraint.from_dict(payload) + assert obj.methods == ["password", "push"] + assert obj.types == ["password"] + assert obj.required is True + assert obj.reauthenticate_in == "PT2H" + + +class TestKnowledgeConstraintEnums: + """Validator tests for `KnowledgeConstraint` (inherits the same enums).""" + + def test_lowercase_methods_accepted(self): + obj = KnowledgeConstraint(methods=["password"]) + assert obj.methods == ["password"] + + def test_lowercase_types_accepted(self): + obj = KnowledgeConstraint(types=["password", "security_question"]) + assert obj.types == ["password", "security_question"] + + def test_uppercase_methods_rejected(self): + with pytest.raises(ValidationError): + KnowledgeConstraint(methods=["PASSWORD"]) + + def test_uppercase_types_rejected(self): + with pytest.raises(ValidationError): + KnowledgeConstraint(types=["PASSWORD"]) + + +class TestPossessionConstraintEnums: + """Validator tests for `PossessionConstraint` (inherits the same enums).""" + + def test_lowercase_methods_accepted(self): + obj = PossessionConstraint(methods=["push", "signed_nonce", "webauthn"]) + assert obj.methods == ["push", "signed_nonce", "webauthn"] + + def test_lowercase_types_accepted(self): + obj = PossessionConstraint(types=["security_key", "phone"]) + assert obj.types == ["security_key", "phone"] + + def test_uppercase_methods_rejected(self): + with pytest.raises(ValidationError): + PossessionConstraint(methods=["PUSH"]) + + def test_uppercase_types_rejected(self): + with pytest.raises(ValidationError): + PossessionConstraint(types=["SECURITY_KEY"]) +
