Skip to content

Add new Common Auth v2 APIs #25

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
38 changes: 32 additions & 6 deletions client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ at = loop.run_until_complete(task)
print(f'API Token: {at.access_token}')
```

To request a particular scope for this access token:

```python
task = authentication.get_api_token(APP_KEY, APP_SECRET, scope=['comms:*'])
at = loop.run_until_complete(task)

print(f'API Token: {at.access_token}')
print(f'Scope: {at.scope}')
```

## Communications Examples

### Get a client access token
Expand All @@ -53,30 +63,45 @@ To get an access token that will be used by the client SDK for an end user to op

```python
import asyncio
from dolbyio_rest_apis import authentication as auth
from dolbyio_rest_apis.communications import authentication

APP_KEY = 'YOUR_APP_KEY'
APP_SECRET = 'YOUR_APP_SECRET'

loop = asyncio.get_event_loop()

task = authentication.get_api_token(APP_KEY, APP_SECRET)
at = loop.run_until_complete(task)
# Request an API Token
task = auth.get_api_token(APP_KEY, APP_SECRET, scope=['comms:client_access_token:create'])
api_token = loop.run_until_complete(task)

print(f'API Token: {api_token.access_token}')

print(f'Access Token: {at.access_token}')
# Request the Client Access Token
task = authentication.get_client_access_token_v2(api_token.access_token, ['*'])
cat = loop.run_until_complete(task)

print(f'Client Access Token: {cat.access_token}')
```

Because most of the APIs are asynchronous, you can write an async function like that:

```python
from dolbyio_rest_apis import authentication as auth
from dolbyio_rest_apis.communications import authentication

APP_KEY = 'YOUR_APP_KEY'
APP_SECRET = 'YOUR_APP_SECRET'

async def get_client_access_token():
at = await authentication.get_client_access_token(APP_KEY, APP_SECRET)
print(f'Access Token: {at.access_token}')
# Request an API Token
api_token = await auth.get_api_token(APP_KEY, APP_SECRET, scope=['comms:client_access_token:create'])

# Request the Client Access Token
cat = await authentication.get_client_access_token_v2(api_token.access_token, ['*'])
print(f'Client Access Token: {cat.access_token}')

return cat.access_token

```

Expand Down Expand Up @@ -104,9 +129,10 @@ participants = [
loop = asyncio.get_event_loop()

# Request an API token
task = authentication.get_api_token(APP_KEY, APP_SECRET)
task = authentication.get_api_token(APP_KEY, APP_SECRET, scope=['comms:conf:create'])
at = loop.run_until_complete(task)

# Create the conference
task = conference.create_conference(
at.access_token,
owner_id,
Expand Down
1 change: 1 addition & 0 deletions client/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ aiohttp>=3.7.4
aiofiles>=0.7.0
aiohttp-retry>=2.4.6
certifi>=2022.12.7
Deprecated>=1.2.14
23 changes: 22 additions & 1 deletion client/src/dolbyio_rest_apis/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
from dolbyio_rest_apis.core.urls import get_api_url
from dolbyio_rest_apis.communications.internal.http_context import CommunicationsHttpContext
from .models import AccessToken
from typing import List

async def get_api_token(
app_key: str,
app_secret: str,
expires_in: int=None,
scope: List[str]=None,
) -> AccessToken:
r"""
To make any API call, you must acquire a JWT (JSON Web Token) format API token.
Expand All @@ -26,8 +28,25 @@ async def get_api_token(
app_key: Your Dolby.io App Key.
app_secret: Your Dolby.io App Secret.
expires_in: (Optional) API token expiration time in seconds.
The maximum value is 86,400, indicating 24 hours.
If no value is specified, the default is 1800, indicating 30 minutes.
The maximum value is 86,400, indicating 24 hours.
scope: (Optional) A list of case-sensitive strings allowing you to control what scope of access the API token should have.
If not specified, the API token will possess unrestricted access to all resources and actions.
The API supports the following scopes:
- comms:client_access_token:create: Allows requesting a client access token.
- comms:conf:create: Allows creating a new conference.
- comms:conf:admin: Allows administrating a conference, including actions
such as Invite, Kick, Send Message, Set Spatial Listener's Audio, and Update Permissions.
- comms:conf:destroy: Allows terminating a live conference.
- comms:monitor:delete: Allows deleting data from the Monitor API, for example, deleting recordings.
- comms:monitor:read: Allows reading data through the Monitor API.
- comms:monitor:download: Allows generating download URLs for data (e.g. recording) through the Monitor API.
- comms:stream:write: Allows starting and stopping RTMP or Real-Time streaming.
- comms:remix:write: Allows remixing recordings.
- comms:remix:read: Allows reading the remix status.
- comms:record:write: Allows starting and stopping recordings.
Incorrect values are omitted. If you want to give the token access to all Communications REST APIs,
you can use a wildcard, such as comms:*

Returns:
An :class:`AccessToken` object.
Expand All @@ -41,6 +60,8 @@ async def get_api_token(
'grant_type': 'client_credentials',
}
add_if_not_none(data, 'expires_in', expires_in)
if scope is not None:
data['scope'] = ' '.join(scope)

async with CommunicationsHttpContext() as http_context:
json_response = await http_context.requests_post_basic_auth(
Expand Down
58 changes: 56 additions & 2 deletions client/src/dolbyio_rest_apis/communications/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@
This module contains the functions to work with the authentication API.
"""

from deprecated import deprecated
from dolbyio_rest_apis.communications.internal.http_context import CommunicationsHttpContext
from dolbyio_rest_apis.core.helpers import add_if_not_none
from dolbyio_rest_apis.core.urls import get_comms_session_url
from dolbyio_rest_apis.core.urls import get_comms_session_url, get_comms_url_v2
from dolbyio_rest_apis.models import AccessToken
from typing import List

@deprecated(reason='''
This function is now deprecated and will be removed in the next release of this SDK.
Please start using :meth:`get_client_access_token_v2` instead.
''')
async def get_client_access_token(
app_key: str,
app_secret: str,
Expand All @@ -19,7 +25,7 @@ async def get_client_access_token(
This API returns an access token that your backend can request on behalf of a client to initialize
the Dolby.io SDK in a secure way.

See: https://docs.dolby.io/communications-apis/reference/get-client-access-token
See: https://docs.dolby.io/communications-apis/reference/get-client-access-token-v1

Args:
app_key: Your Dolby.io App Key.
Expand Down Expand Up @@ -49,3 +55,51 @@ async def get_client_access_token(
)

return AccessToken(json_response)

async def get_client_access_token_v2(
access_token: str,
session_scope: List[str],
external_id: str=None,
expires_in: int=None,
) -> AccessToken:
r"""
This API returns an access token that your backend can request on behalf of a client to initialize
the Dolby.io SDK in a secure way.

See: https://docs.dolby.io/communications-apis/reference/get-client-access-token

Args:
access_token: Access token to use for authentication.
session_scope: A list of case-sensitive strings allowing you to control
what scope of access the client access token should have.
The API supports the following scopes:
- conf:create: Allows creating a new conference.
- notifications:set: Allows the client to subscribe to events.
- file:convert: Allows converting files.
- session:update: Allows updating the participant's name and avatar URL.
Incorrect values are omitted. If you want to give the token access to all scopes, you can use a wildcard, such as *.
external_id: (Optional) The unique identifier of the participant who requests the token.
expires_in: (Optional) Access token expiration time in seconds.
If no value is specified, the default is 3,600, indicating one hour.
The maximum value is 86,400, indicating 24 hours.
Returns:
An :class:`AccessToken` object.

Raises:
HttpRequestError: If a client error one occurred.
HTTPError: If one occurred.
"""
payload = {}
add_if_not_none(payload, 'externalId', external_id)
add_if_not_none(payload, 'expires_in', expires_in)
if session_scope is not None:
payload['sessionScope'] = ' '.join(session_scope)

async with CommunicationsHttpContext() as http_context:
json_response = await http_context.requests_post(
access_token=access_token,
url=f'{get_comms_url_v2()}/client-access-token',
payload=payload,
)

return AccessToken(json_response)
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ async def _requests_post_put(
url: str,
method: str,
payload: Any=None,
extra_headers: Dict[str, str]=None,
) -> Any or None:
r"""
Sends a POST or PUT request.
Expand All @@ -36,6 +37,7 @@ async def _requests_post_put(
url: Where to send the request to.
method: HTTP method, POST or PUT.
payload: (Optional) Content of the request.
extra_headers: (Optional) Add extra HTTP headers in the request.

Returns:
The JSON response if any or None.
Expand All @@ -51,6 +53,9 @@ async def _requests_post_put(
'Authorization': f'Bearer {access_token}',
}

if extra_headers is not None:
headers.update(extra_headers)

if payload is None:
payload = '{}' # The REST APIs don't support an empty payload
else:
Expand Down Expand Up @@ -97,6 +102,7 @@ async def requests_post(
access_token: str,
url: str,
payload: Any=None,
extra_headers: Dict[str, str]=None,
) -> Any or None:
r"""
Sends a POST request.
Expand All @@ -105,6 +111,7 @@ async def requests_post(
access_token: The Access Token to use for authentication.
url: Where to send the request to.
payload: (Optional) Content of the request.
extra_headers: (Optional) Add extra HTTP headers in the request.

Returns:
The JSON response if any or None.
Expand All @@ -118,7 +125,8 @@ async def requests_post(
access_token=access_token,
url=url,
method='POST',
payload=payload
payload=payload,
extra_headers=extra_headers,
)

async def requests_post_basic_auth(
Expand Down
9 changes: 6 additions & 3 deletions client/src/dolbyio_rest_apis/core/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
API_URL = 'api.dolby.io'

COMMS_URL = 'comms.api.dolby.io'
COMMS_SESSION_URL = 'session.voxeet.com/v1'
COMMS_SESSION_URL = 'session.voxeet.com'

SAPI_URL = 'api.millicast.com'

Expand All @@ -17,16 +17,19 @@
def get_api_url() -> str:
return f'https://{API_URL}/v1'

def get_comms_url_v1() -> str:
return f'https://{COMMS_URL}/v1'

def get_comms_monitor_url() -> str:
return f'https://{COMMS_URL}/v1/monitor'
return f'{get_comms_url_v1()}/monitor'

def get_comms_url_v2(region: str = None) -> str:
if region is None:
return f'https://{COMMS_URL}/v2'
return f'https://{region}.{COMMS_URL}/v2'

def get_comms_session_url() -> str:
return f'https://{COMMS_SESSION_URL}'
return f'https://{COMMS_SESSION_URL}/v1'

def get_rts_url() -> str:
return f'https://{SAPI_URL}'
Expand Down
Loading