Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,22 @@
cast,
Tuple,
)
import six

from msrest.serialization import TZ_UTC
from .utils import create_access_token

class CommunicationTokenCredential(object):
"""Credential type used for authenticating to an Azure Communication service.
:param str token: The token used to authenticate to an Azure Communication service
:raises: TypeError
:param communication_token_refresh_options: The token used to authenticate to an Azure Communication service
:type communication_token_refresh_options: ~azure.communication.chat.CommunicationTokenRefreshOptions
"""

ON_DEMAND_REFRESHING_INTERVAL_MINUTES = 2

def __init__(self,
token, # type: str
token_refresher=None
communication_token_refresh_options
):
# type: (str) -> None
if not isinstance(token, six.string_types):
raise TypeError("token must be a string.")
self._token = create_access_token(token)
self._token_refresher = token_refresher
self._token = communication_token_refresh_options.get_token()
self._token_refresher = communication_token_refresh_options.get_token_refresher()
self._lock = Condition(Lock())
self._some_thread_refreshing = False

Expand Down Expand Up @@ -70,7 +65,6 @@ def get_token(self):
self._lock.notify_all()

raise

return self._token

def _wait_till_inprogress_thread_finish_refreshing(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,23 @@
cast,
Tuple,
)
import six

from msrest.serialization import TZ_UTC
from .utils import create_access_token

class CommunicationTokenCredential(object):
"""Credential type used for authenticating to an Azure Communication service.
:param str token: The token used to authenticate to an Azure Communication service
:param communication_token_refresh_options: The token used to authenticate to an Azure Communication service
:type communication_token_refresh_options: ~azure.communication.chat.aio.CommunicationTokenRefreshOptions
:raises: TypeError
"""

ON_DEMAND_REFRESHING_INTERVAL_MINUTES = 2

def __init__(self,
token, # type: str
token_refresher=None
communication_token_refresh_options
):
# type: (str) -> None
if not isinstance(token, six.string_types):
raise TypeError("token must be a string.")
self._token = create_access_token(token)
self._token_refresher = token_refresher
self._token = communication_token_refresh_options.get_token()
self._token_refresher = communication_token_refresh_options.get_token_refresher()
self._lock = Condition(Lock())
self._some_thread_refreshing = False

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------
from typing import ( # pylint: disable=unused-import
cast,
Tuple,
)
import six
from .utils import create_access_token

class CommunicationTokenRefreshOptions(object):
"""Options for refreshing CommunicationTokenCredential.
:param str token: The token used to authenticate to an Azure Communication service
:param token_refresher: The token refresher to provide capacity to fetch fresh token
:raises: TypeError
"""

def __init__(self,
token, # type: str
token_refresher=None
):
# type: (str) -> None
if not isinstance(token, six.string_types):
raise TypeError("token must be a string.")
self._token = token
self._token_refresher = token_refresher

def get_token(self):
"""Return the the serialized JWT token."""
return create_access_token(self._token)

def get_token_refresher(self):
"""Return the token refresher to provide capacity to fetch fresh token."""
return self._token_refresher
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from unittest import TestCase
from unittest.mock import MagicMock
from azure.communication.administration._shared.user_credential import CommunicationTokenCredential
from azure.communication.administration._shared.user_token_refresh_options import CommunicationTokenRefreshOptions
from azure.communication.administration._shared.utils import create_access_token


Expand All @@ -18,24 +19,29 @@ class TestCommunicationTokenCredential(TestCase):


def test_communicationtokencredential_decodes_token(self):
credential = CommunicationTokenCredential(self.sample_token)
refresh_options = CommunicationTokenRefreshOptions(self.sample_token)
credential = CommunicationTokenCredential(refresh_options)
access_token = credential.get_token()

self.assertEqual(access_token.token, self.sample_token)

def test_communicationtokencredential_throws_if_invalid_token(self):
self.assertRaises(ValueError, lambda: CommunicationTokenCredential("foo.bar.tar"))
refresh_options = CommunicationTokenRefreshOptions("foo.bar.tar")
self.assertRaises(ValueError, lambda: CommunicationTokenCredential(refresh_options))

def test_communicationtokencredential_throws_if_nonstring_token(self):
self.assertRaises(TypeError, lambda: CommunicationTokenCredential(454))
refresh_options = CommunicationTokenRefreshOptions(454):
self.assertRaises(TypeError, lambda: CommunicationTokenCredential(refresh_options)

def test_communicationtokencredential_static_token_returns_expired_token(self):
credential = CommunicationTokenCredential(self.expired_token)
refresh_options = CommunicationTokenRefreshOptions(self.expired_token)
credential = CommunicationTokenCredential(refresh_options)

self.assertEqual(credential.get_token().token, self.expired_token)

def test_communicationtokencredential_token_expired_refresh_called(self):
refresher = MagicMock(return_value=self.sample_token)
refresh_options = CommunicationTokenRefreshOptions(self.sample_token, refresher)
access_token = CommunicationTokenCredential(
self.expired_token,
token_refresher=refresher).get_token()
Expand All @@ -45,9 +51,8 @@ def test_communicationtokencredential_token_expired_refresh_called(self):

def test_communicationtokencredential_token_expired_refresh_called_asnecessary(self):
refresher = MagicMock(return_value=create_access_token(self.expired_token))
credential = CommunicationTokenCredential(
self.expired_token,
token_refresher=refresher)
refresh_options = CommunicationTokenRefreshOptions(self.expired_token, refresher)
credential = CommunicationTokenCredential(refresh_options)

credential.get_token()
access_token = credential.get_token()
Expand Down
3 changes: 2 additions & 1 deletion sdk/communication/azure-communication-chat/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ from azure.communication.chat import ChatClient, CommunicationTokenCredential
# Your unique Azure Communication service endpoint
endpoint = "https://<RESOURCE_NAME>.communcationservices.azure.com"
token = "<token>"
chat_client = ChatClient(endpoint, CommunicationTokenCredential(token))
refresh_options = CommunicationTokenRefreshOptions(token)
chat_client = ChatClient(endpoint, CommunicationTokenCredential(refresh_options))
```

## Create Chat Thread Client
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
ChatThreadInfo,
)
from ._shared.user_credential import CommunicationTokenCredential
from ._shared.user_token_refresh_options import CommunicationTokenRefreshOptions
from ._models import (
ChatThreadMember,
ChatMessage,
Expand All @@ -25,6 +26,7 @@
'ChatThread',
'ChatThreadInfo',
'CommunicationTokenCredential',
'CommunicationTokenRefreshOptions',
'ChatThreadMember',
'CommunicationUserIdentifier',
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,22 @@
cast,
Tuple,
)
import six

from msrest.serialization import TZ_UTC
from .utils import create_access_token

class CommunicationTokenCredential(object):
"""Credential type used for authenticating to an Azure Communication service.
:param str token: The token used to authenticate to an Azure Communication service
:raises: TypeError
:param communication_token_refresh_options: The token used to authenticate to an Azure Communication service
:type communication_token_refresh_options: ~azure.communication.chat.CommunicationTokenRefreshOptions
"""

ON_DEMAND_REFRESHING_INTERVAL_MINUTES = 2

def __init__(self,
token, # type: str
token_refresher=None
communication_token_refresh_options
):
# type: (str) -> None
if not isinstance(token, six.string_types):
raise TypeError("token must be a string.")
self._token = create_access_token(token)
self._token_refresher = token_refresher
self._token = communication_token_refresh_options.get_token()
self._token_refresher = communication_token_refresh_options.get_token_refresher()
self._lock = Condition(Lock())
self._some_thread_refreshing = False

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,22 @@
Tuple,
)

import six

from msrest.serialization import TZ_UTC
from .utils import create_access_token

class CommunicationTokenCredential(object):
"""Credential type used for authenticating to an Azure Communication service.
:param str token: The token used to authenticate to an Azure Communication service
:param communication_token_refresh_options: The token used to authenticate to an Azure Communication service
:type communication_token_refresh_options: ~azure.communication.chat.aio.CommunicationTokenRefreshOptions
:raises: TypeError
"""

ON_DEMAND_REFRESHING_INTERVAL_MINUTES = 2

def __init__(self,
token, # type: str
token_refresher=None
communication_token_refresh_options
):
# type: (str) -> None
if not isinstance(token, six.string_types):
raise TypeError("token must be a string.")
self._token = create_access_token(token)
self._token_refresher = token_refresher
self._token = communication_token_refresh_options.get_token()
self._token_refresher = communication_token_refresh_options.get_token_refresher()
self._lock = Condition(Lock())
self._some_thread_refreshing = False

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------
from typing import ( # pylint: disable=unused-import
cast,
Tuple,
)
import six
from .utils import create_access_token

class CommunicationTokenRefreshOptions(object):
"""Options for refreshing CommunicationTokenCredential.
:param str token: The token used to authenticate to an Azure Communication service
:param token_refresher: The token refresher to provide capacity to fetch fresh token
:raises: TypeError
"""

def __init__(self,
token, # type: str
token_refresher=None
):
# type: (str) -> None
if not isinstance(token, six.string_types):
raise TypeError("token must be a string.")
self._token = token
self._token_refresher = token_refresher

def get_token(self):
"""Return the the serialized JWT token."""
return create_access_token(self._token)

def get_token_refresher(self):
"""Return the token refresher to provide capacity to fetch fresh token."""
return self._token_refresher
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
from ._chat_client_async import ChatClient
from ._chat_thread_client_async import ChatThreadClient
from .._shared.user_credential_async import CommunicationTokenCredential
from .._shared.user_token_refresh_options import CommunicationTokenRefreshOptions

__all__ = [
"ChatClient",
"ChatThreadClient",
"CommunicationTokenCredential"
"CommunicationTokenCredential",
"CommunicationTokenRefreshOptions"
]
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ class ChatClientSamples(object):

def create_chat_client(self):
# [START create_chat_client]
from azure.communication.chat import ChatClient, CommunicationTokenCredential
chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token))
from azure.communication.chat import ChatClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions
refresh_options = CommunicationTokenRefreshOptions(self.token)
chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options))
# [END create_chat_client]

def create_thread(self):
Expand All @@ -56,10 +57,12 @@ def create_thread(self):
ChatClient,
ChatThreadMember,
CommunicationUserIdentifier,
CommunicationTokenCredential
CommunicationTokenCredential,
CommunicationTokenRefreshOptions
)

chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token))
refresh_options = CommunicationTokenRefreshOptions(self.token)
chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options))

topic = "test topic"
members = [ChatThreadMember(
Expand All @@ -75,31 +78,34 @@ def create_thread(self):

def get_chat_thread_client(self):
# [START get_chat_thread_client]
from azure.communication.chat import ChatClient, CommunicationTokenCredential
from azure.communication.chat import ChatClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions

chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token))
refresh_options = CommunicationTokenRefreshOptions(self.token)
chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options))
chat_thread_client = chat_client.get_chat_thread_client(self._thread_id)
# [END get_chat_thread_client]

print("chat_thread_client created with thread id: ", chat_thread_client.thread_id)

def get_thread(self):
# [START get_thread]
from azure.communication.chat import ChatClient, CommunicationTokenCredential
from azure.communication.chat import ChatClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions

chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token))
refresh_options = CommunicationTokenRefreshOptions(self.token)
chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options))
chat_thread = chat_client.get_chat_thread(self._thread_id)
# [END get_thread]

print("get_thread succeeded, thread id: " + chat_thread.id + ", thread topic: " + chat_thread.topic)

def list_threads(self):
# [START list_threads]
from azure.communication.chat import ChatClient, CommunicationTokenCredential
from azure.communication.chat import ChatClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions
from datetime import datetime, timedelta
import pytz

chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token))
refresh_options = CommunicationTokenRefreshOptions(self.token)
chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options))
start_time = datetime.utcnow() - timedelta(days=2)
start_time = start_time.replace(tzinfo=pytz.utc)
chat_thread_infos = chat_client.list_chat_threads(results_per_page=5, start_time=start_time)
Expand All @@ -111,9 +117,10 @@ def list_threads(self):

def delete_thread(self):
# [START delete_thread]
from azure.communication.chat import ChatClient, CommunicationTokenCredential
from azure.communication.chat import ChatClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions

chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token))
refresh_options = CommunicationTokenRefreshOptions(self.token)
chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options))
chat_client.delete_chat_thread(self._thread_id)
# [END delete_thread]

Expand Down
Loading