Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion sdk/communication/azure-communication-identity/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
# Release History

## 1.6.0 (Unreleased)
## 2.0.0 (Unreleased)

### Features Added

- Added support for service API version `2026-09-23`, which is now the default. This version is
functionally equivalent to `2025-06-30`.
- Added support for a new communication identifier `TeamsExtensionUserIdentifier`.
- New identifier maps rawIds with format `8:acs:{resourceId}_{tenantId}_{userId}`.
- With this version, rawId starting with `8:acs` may be either `CommunicationUserIdentifier` or new `TeamsExtensionUserIdentifier`.
- Added `IsAnonymous` and `AssertedId` properties to the communication identifier `PhoneNumberIdentifier`.
- `IsAnonymous` is used for anonymous numbers with rawId equals to `4:anonymous`.
- `AssertedId` is used when the same number is used several times in the same call. It contains value after the last underscore `_` character in the phone number. It is null otherwise.

### Other Changes

- The service layer is now generated from TypeSpec instead of Swagger/AutoRest. There are no
changes to the public API surface: method names, parameters, and return types are unchanged,
and `AccessToken.expires_on` continues to carry the expiry string exactly as returned by the
service.

## 1.5.1 (Unreleased)

### Features Added
Expand Down
6 changes: 3 additions & 3 deletions sdk/communication/azure-communication-identity/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
include *.md
include azure/__init__.py
include azure/communication/__init__.py
include LICENSE
include azure/communication/identity/py.typed
recursive-include tests *.py
recursive-include samples *.py *.md
include azure/communication/identity/py.typed
include azure/__init__.py
include azure/communication/__init__.py
11 changes: 11 additions & 0 deletions sdk/communication/azure-communication-identity/_metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"apiVersion": "2026-09-23",
"apiVersions": {
"Azure.Communication.Identity": "2026-09-23"
},
"commit": "1893171028aed5a757fc78c2d4aa439c14df4afc",
"repository_url": "https://github.com/Azure/azure-rest-api-specs",
"typespec_src": "specification/communication/data-plane/Identity",
"emitterVersion": "0.63.6",
"httpClientPythonVersion": "^0.37.1"
}
2 changes: 2 additions & 0 deletions sdk/communication/azure-communication-identity/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
```py
```
Comment on lines +1 to +2
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiMdSha256: 4f975ce96bb34064e16820c7565f93dd884f6d02f76ad1b913a9ed1a8eff2e83
packageVersion: 1.6.0
parserVersion: 0.3.31
pythonVersion: 3.13.15
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"CrossLanguagePackageId": "Azure.Communication.Identity",
"CrossLanguageDefinitionId": {
"azure.communication.identity.models.CommunicationError": "Azure.Communication.Identity.CommunicationError",
"azure.communication.identity.models.CommunicationErrorResponse": "Azure.Communication.Identity.CommunicationErrorResponse",
"azure.communication.identity.models.CommunicationIdentity": "Azure.Communication.Identity.CommunicationIdentity",
"azure.communication.identity.models.CommunicationIdentityAccessToken": "Azure.Communication.Identity.CommunicationIdentityAccessToken",
"azure.communication.identity.models.CommunicationIdentityAccessTokenRequest": "Azure.Communication.Identity.CommunicationIdentityAccessTokenRequest",
"azure.communication.identity.models.CommunicationIdentityAccessTokenResult": "Azure.Communication.Identity.CommunicationIdentityAccessTokenResult",
"azure.communication.identity.models.CommunicationIdentityCreateRequest": "Azure.Communication.Identity.CommunicationIdentityCreateRequest",
"azure.communication.identity.models.TeamsExtensionAssignmentCreateOrUpdateRequest": "Azure.Communication.Identity.TeamsExtensionAssignmentCreateOrUpdateRequest",
"azure.communication.identity.models.TeamsExtensionAssignmentResponse": "Azure.Communication.Identity.TeamsExtensionAssignmentResponse",
"azure.communication.identity.models.TeamsExtensionExchangeTokenRequest": "Azure.Communication.Identity.TeamsExtensionExchangeTokenRequest",
"azure.communication.identity.models.TeamsUserExchangeTokenRequest": "Azure.Communication.Identity.TeamsUserExchangeTokenRequest",
"azure.communication.identity.models.CommunicationTokenScope": "Azure.Communication.Identity.CommunicationIdentityTokenScope",
"azure.communication.identity.models.TeamsExtensionPrincipalType": "Azure.Communication.Identity.TeamsExtensionPrincipalType",
"azure.communication.identity.operations.IdentityOperationsOperations.create": "Azure.Communication.Identity.IdentityOperations.create",
"azure.communication.identity.aio.operations.IdentityOperationsOperations.create": "Azure.Communication.Identity.IdentityOperations.create",
"azure.communication.identity.operations.IdentityOperationsOperations.delete": "Azure.Communication.Identity.IdentityOperations.delete",
"azure.communication.identity.aio.operations.IdentityOperationsOperations.delete": "Azure.Communication.Identity.IdentityOperations.delete",
"azure.communication.identity.operations.IdentityOperationsOperations.revoke_access_tokens": "Azure.Communication.Identity.IdentityOperations.revokeAccessTokens",
"azure.communication.identity.aio.operations.IdentityOperationsOperations.revoke_access_tokens": "Azure.Communication.Identity.IdentityOperations.revokeAccessTokens",
"azure.communication.identity.operations.IdentityOperationsOperations.issue_access_token": "Azure.Communication.Identity.IdentityOperations.issueAccessToken",
"azure.communication.identity.aio.operations.IdentityOperationsOperations.issue_access_token": "Azure.Communication.Identity.IdentityOperations.issueAccessToken",
"azure.communication.identity.operations.TeamsUserOperationsOperations.exchange_teams_user_access_token": "Azure.Communication.Identity.TeamsUserOperations.exchangeTeamsUserAccessToken",
"azure.communication.identity.aio.operations.TeamsUserOperationsOperations.exchange_teams_user_access_token": "Azure.Communication.Identity.TeamsUserOperations.exchangeTeamsUserAccessToken",
"azure.communication.identity.operations.TeamsExtensionOperationsOperations.exchange_token": "Azure.Communication.Identity.TeamsExtensionOperations.exchangeToken",
"azure.communication.identity.aio.operations.TeamsExtensionOperationsOperations.exchange_token": "Azure.Communication.Identity.TeamsExtensionOperations.exchangeToken",
"azure.communication.identity.operations.TeamsExtensionOperationsOperations.get_assignment": "Azure.Communication.Identity.TeamsExtensionOperations.getAssignment",
"azure.communication.identity.aio.operations.TeamsExtensionOperationsOperations.get_assignment": "Azure.Communication.Identity.TeamsExtensionOperations.getAssignment",
"azure.communication.identity.operations.TeamsExtensionOperationsOperations.upsert_assignment": "Azure.Communication.Identity.TeamsExtensionOperations.upsertAssignment",
"azure.communication.identity.aio.operations.TeamsExtensionOperationsOperations.upsert_assignment": "Azure.Communication.Identity.TeamsExtensionOperations.upsertAssignment",
"azure.communication.identity.operations.TeamsExtensionOperationsOperations.delete_assignment": "Azure.Communication.Identity.TeamsExtensionOperations.deleteAssignment",
"azure.communication.identity.aio.operations.TeamsExtensionOperationsOperations.delete_assignment": "Azure.Communication.Identity.TeamsExtensionOperations.deleteAssignment"
},
"CrossLanguageVersion": "6be142630ab4"
}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__path__ = __import__("pkgutil").extend_path(__path__, __name__)
__path__ = __import__("pkgutil").extend_path(__path__, __name__) # type: ignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__path__ = __import__("pkgutil").extend_path(__path__, __name__)
__path__ = __import__("pkgutil").extend_path(__path__, __name__) # type: ignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class ApiVersion(str, Enum, metaclass=CaseInsensitiveEnumMeta):
V2022_06_01 = "2022-06-01"
V2022_10_01 = "2022-10-01"
V2023_10_01 = "2023-10-01"
V2025_06_30 = "2025-06-30"
V2026_09_23 = "2026-09-23"


DEFAULT_VERSION = ApiVersion.V2023_10_01
DEFAULT_VERSION = ApiVersion.V2026_09_23
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,21 @@
from azure.core.tracing.decorator import distributed_trace
from azure.core.credentials import AccessToken
from ._generated._client import (
CommunicationIdentityClient as CommunicationIdentityClientGen,
IdentityClient as CommunicationIdentityClientGen,
)
from ._shared.auth_policy_utils import get_authentication_policy
from ._shared.utils import parse_connection_str
from ._shared.models import CommunicationUserIdentifier
from ._version import SDK_MONIKER
from ._api_versions import DEFAULT_VERSION
from ._utils import convert_timedelta_to_mins
from ._utils import (
_ACCEPT_JSON,
BodylessCreateContentTypePolicy,
build_token_request_body,
extract_create_content_type,
merge_headers,
to_access_token,
)
from ._generated.models import CommunicationTokenScope

if TYPE_CHECKING:
Expand Down Expand Up @@ -56,20 +63,19 @@ def __init__(
raise ValueError("You need to provide account shared key to authenticate.")
self._endpoint = endpoint
self._api_version = kwargs.pop("api_version", DEFAULT_VERSION)
per_call_policies = list(kwargs.pop("per_call_policies", None) or [])
per_call_policies.append(BodylessCreateContentTypePolicy())
self._identity_service_client = CommunicationIdentityClientGen(
self._endpoint,
api_version=self._api_version,
authentication_policy=get_authentication_policy(endpoint, credential),
sdk_moniker=SDK_MONIKER,
per_call_policies=per_call_policies,
**kwargs
)

@classmethod
def from_connection_string(
cls,
conn_str: str,
**kwargs: Any
) -> "CommunicationIdentityClient":
def from_connection_string(cls, conn_str: str, **kwargs: Any) -> "CommunicationIdentityClient":
"""Create CommunicationIdentityClient from a Connection String.

:param str conn_str: A connection string to an Azure Communication Service resource.
Expand All @@ -89,14 +95,17 @@ def create_user(self, **kwargs) -> CommunicationUserIdentifier:
:return: CommunicationUserIdentifier
:rtype: ~azure.communication.identity.CommunicationUserIdentifier
"""
identity_access_token = self._identity_service_client.communication_identity.create(**kwargs)
identity_access_token = self._identity_service_client.identity_operations.create(
**extract_create_content_type(kwargs)
)

return CommunicationUserIdentifier(identity_access_token.identity.id, raw_id=identity_access_token.identity.id)

@distributed_trace
def create_user_and_token(
self,
scopes: List[Union[str, CommunicationTokenScope]], *,
scopes: List[Union[str, CommunicationTokenScope]],
*,
token_expires_in: Optional[timedelta] = None,
**kwargs: Any
) -> Tuple[CommunicationUserIdentifier, AccessToken]:
Expand All @@ -111,44 +120,37 @@ def create_user_and_token(
:rtype:
tuple of (~azure.communication.identity.CommunicationUserIdentifier, ~azure.core.credentials.AccessToken)
"""
request_body = {
"createTokenWithScopes": scopes,
"expiresInMinutes": convert_timedelta_to_mins(token_expires_in),
}
identity_access_token = self._identity_service_client.communication_identity.create(
request_body = build_token_request_body("createTokenWithScopes", scopes, token_expires_in)
identity_access_token = self._identity_service_client.identity_operations.create(
body=request_body, **kwargs # type: ignore
)

user_identifier = CommunicationUserIdentifier(
identity_access_token.identity.id, raw_id=identity_access_token.identity.id
)
access_token = AccessToken(
identity_access_token.access_token.token,
identity_access_token.access_token.expires_on,
)
access_token = to_access_token(identity_access_token["accessToken"])

return user_identifier, access_token

@distributed_trace
def delete_user(
self,
user: CommunicationUserIdentifier,
**kwargs: Any
) -> None:
def delete_user(self, user: CommunicationUserIdentifier, **kwargs: Any) -> None:
"""Triggers revocation event for user and deletes all its data.

:param user: Azure Communication User to delete
:type user: ~azure.communication.identity.CommunicationUserIdentifier
:return: None
:rtype: None
"""
self._identity_service_client.communication_identity.delete(user.properties["id"], **kwargs)
self._identity_service_client.identity_operations.delete(
user.properties["id"], **merge_headers(kwargs, _ACCEPT_JSON)
)

@distributed_trace
def get_token(
self,
user: CommunicationUserIdentifier,
scopes: List[Union[str, CommunicationTokenScope]], *,
scopes: List[Union[str, CommunicationTokenScope]],
*,
token_expires_in: Optional[timedelta] = None,
**kwargs: Any
) -> AccessToken:
Expand All @@ -164,41 +166,30 @@ def get_token(
:return: AccessToken
:rtype: ~azure.core.credentials.AccessToken
"""
request_body = {
"scopes": scopes,
"expiresInMinutes": convert_timedelta_to_mins(token_expires_in),
}
request_body = build_token_request_body("scopes", scopes, token_expires_in)

access_token = self._identity_service_client.communication_identity.issue_access_token(
access_token = self._identity_service_client.identity_operations.issue_access_token(
user.properties["id"], body=request_body, **kwargs # type: ignore
)

return AccessToken(access_token.token, access_token.expires_on)
return to_access_token(access_token)

@distributed_trace
def revoke_tokens(
self,
user: CommunicationUserIdentifier,
**kwargs: Any
) -> None:
def revoke_tokens(self, user: CommunicationUserIdentifier, **kwargs: Any) -> None:
"""Schedule revocation of all tokens of an identity.

:param user: Azure Communication User.
:type user: ~azure.communication.identity.CommunicationUserIdentifier.
:return: None
:rtype: None
"""
return self._identity_service_client.communication_identity.revoke_access_tokens(
user.properties["id"] if user else None, **kwargs # type: ignore
return self._identity_service_client.identity_operations.revoke_access_tokens(
user.properties["id"] if user else None, **merge_headers(kwargs, _ACCEPT_JSON) # type: ignore
)

@distributed_trace
def get_token_for_teams_user(
self,
aad_token: str,
client_id: str,
user_object_id: str,
**kwargs: Any
self, aad_token: str, client_id: str, user_object_id: str, **kwargs: Any
) -> AccessToken:
"""Exchanges an Azure AD access token of a Teams User for a new Communication Identity access token.

Expand All @@ -220,8 +211,8 @@ def get_token_for_teams_user(
"userId": user_object_id,
}

access_token = self._identity_service_client.communication_identity.exchange_teams_user_access_token(
access_token = self._identity_service_client.teams_user_operations.exchange_teams_user_access_token(
body=request_body, **kwargs # type: ignore
)

return AccessToken(access_token.token, access_token.expires_on)
return to_access_token(access_token)
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,31 @@
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# Code generated by Microsoft (R) AutoRest Code Generator.
# Code generated by Microsoft (R) Python Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------
# pylint: disable=wrong-import-position

from ._client import CommunicationIdentityClient
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from ._patch import * # pylint: disable=unused-wildcard-import

from ._client import IdentityClient # type: ignore
from ._version import VERSION

__version__ = VERSION

try:
from ._patch import __all__ as _patch_all
from ._patch import * # pylint: disable=unused-wildcard-import
from ._patch import *
except ImportError:
_patch_all = []
from ._patch import patch_sdk as _patch_sdk

__all__ = [
"CommunicationIdentityClient",
"IdentityClient",
]
__all__.extend([p for p in _patch_all if p not in __all__])
__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore

_patch_sdk()
Loading