Skip to content

Commit 84f91d2

Browse files
Adding Support For Federated Login
1 parent 8262ce4 commit 84f91d2

File tree

4 files changed

+157
-0
lines changed

4 files changed

+157
-0
lines changed

auth0/authentication/get_token.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,3 +277,51 @@ def backchannel_login(
277277
"grant_type": grant_type,
278278
},
279279
)
280+
281+
def federated_login(
282+
self,
283+
subject_token_type: str,
284+
subject_token: str,
285+
requested_token_type: str,
286+
login_hint: str | None = None,
287+
scope: str | None = None,
288+
connection: str | None = None,
289+
grant_type: str = "urn:auth0:params:oauth:grant-type:token-exchange:federated-connection-access-token"
290+
) -> Any:
291+
"""Calls /oauth/token endpoint with federated-connection-access-token grant type
292+
293+
Args:
294+
subject_token_type (str): String containing the typpe of token.
295+
296+
subject_token (str): String containing the value of subject_token_type.
297+
298+
requested_token_type (str): String containing the type of rquested token.
299+
300+
connection (str, optional): Denotes the name of a social identity provider configured to your application
301+
302+
login_hint (str, optional): String containing information about the user to contact for authentication.
303+
304+
scope(str, optional): String value of the different scopes the client is asking for.
305+
Multiple scopes are separated with whitespace.
306+
307+
grant_type (str): Denotes the flow you're using. For Federated Connection Access token use
308+
urn:auth0:params:oauth:grant-type:token-exchange:federated-connection-access-token
309+
310+
311+
Returns:
312+
access_token, scope, issued_token_type, token_type
313+
"""
314+
315+
return self.authenticated_post(
316+
f"{self.protocol}://{self.domain}/oauth/token",
317+
data={
318+
"client_id": self.client_id,
319+
"grant_type": grant_type,
320+
"subject_token_type": subject_token_type,
321+
"subject_token": subject_token,
322+
"requested_token_type": requested_token_type,
323+
"login_hint": login_hint,
324+
"connection": connection,
325+
"scope": scope,
326+
},
327+
)

auth0/management/users.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,3 +538,46 @@ def delete_authentication_method_by_id(
538538

539539
url = self._url(f"{user_id}/authentication-methods/{authentication_method_id}")
540540
return self.client.delete(url)
541+
542+
def list_tokensets(
543+
self, id: str, page: int = 0, per_page: int = 25, include_totals: bool = True
544+
):
545+
"""List all the tokenset(s) associated to the user.
546+
547+
Args:
548+
id (str): The user's id.
549+
550+
page (int, optional): The result's page number (zero based). By default,
551+
retrieves the first page of results.
552+
553+
per_page (int, optional): The amount of entries per page. By default,
554+
retrieves 25 results per page.
555+
556+
include_totals (bool, optional): True if the query summary is
557+
to be included in the result, False otherwise. Defaults to True.
558+
559+
See https://auth0.com/docs/api/management/v2#!/Users/get_tokensets
560+
"""
561+
562+
params = {
563+
"per_page": per_page,
564+
"page": page,
565+
"include_totals": str(include_totals).lower(),
566+
}
567+
url = self._url(f"{id}/tokensets")
568+
return self.client.get(url, params=params)
569+
570+
def delete_tokenset_by_id(
571+
self, user_id: str, tokenset_id: str
572+
) -> Any:
573+
"""Deletes an tokenset by ID.
574+
575+
Args:
576+
user_id (str): The user_id to delete an authentication method by ID for.
577+
tokenset_id (str): The tokenset_id to delete an tokenset by ID for.
578+
579+
See: https://auth0.com/docs/api/management/v2#!/Users/delete_tokenset_by_id
580+
"""
581+
582+
url = self._url(f"{user_id}/tokensets/{tokenset_id}")
583+
return self.client.delete(url)

auth0/test/authentication/test_get_token.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,4 +334,37 @@ def test_backchannel_login(self, mock_post):
334334
"auth_req_id": "reqid",
335335
"grant_type": "urn:openid:params:grant-type:ciba",
336336
},
337+
)
338+
339+
@mock.patch("auth0.rest.RestClient.post")
340+
def test_federated_login(self, mock_post):
341+
g = GetToken("my.domain.com", "cid", client_secret="csec")
342+
343+
g.federated_login(
344+
grant_type="urn:auth0:params:oauth:grant-type:token-exchange:federated-connection-access-token",
345+
subject_token_type="urn:ietf:params:oauth:token-type:refresh_token",
346+
subject_token="refid",
347+
requested_token_type="http://auth0.com/oauth/token-type/federated-connection-access-token",
348+
connection="google-oauth2",
349+
login_hint="idp_user_id"
350+
)
351+
352+
args, kwargs = mock_post.call_args
353+
354+
print(kwargs["data"])
355+
356+
self.assertEqual(args[0], "https://my.domain.com/oauth/token")
357+
self.assertEqual(
358+
kwargs["data"],
359+
{
360+
"grant_type": "urn:auth0:params:oauth:grant-type:token-exchange:federated-connection-access-token",
361+
"client_id": "cid",
362+
"client_secret": "csec",
363+
"subject_token_type": "urn:ietf:params:oauth:token-type:refresh_token",
364+
"subject_token": "refid",
365+
"requested_token_type": "http://auth0.com/oauth/token-type/federated-connection-access-token",
366+
"connection": "google-oauth2",
367+
"login_hint": "idp_user_id",
368+
"scope": None,
369+
},
337370
)

auth0/test/management/test_users.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,3 +403,36 @@ def test_delete_authentication_method_by_id(self, mock_rc):
403403
mock_instance.delete.assert_called_with(
404404
"https://domain/api/v2/users/user_id/authentication-methods/authentication_method_id"
405405
)
406+
407+
@mock.patch("auth0.management.users.RestClient")
408+
def test_list_tokensets(self, mock_rc):
409+
mock_instance = mock_rc.return_value
410+
411+
u = Users(domain="domain", token="jwttoken")
412+
u.list_tokensets("an-id")
413+
414+
args, kwargs = mock_instance.get.call_args
415+
self.assertEqual("https://domain/api/v2/users/an-id/tokensets", args[0])
416+
self.assertEqual(
417+
kwargs["params"], {"per_page": 25, "page": 0, "include_totals": "true"}
418+
)
419+
420+
u.list_tokensets(id="an-id", page=1, per_page=50, include_totals=False)
421+
422+
args, kwargs = mock_instance.get.call_args
423+
424+
self.assertEqual("https://domain/api/v2/users/an-id/tokensets", args[0])
425+
self.assertEqual(
426+
kwargs["params"], {"per_page": 50, "page": 1, "include_totals": "false"}
427+
)
428+
429+
@mock.patch("auth0.management.users.RestClient")
430+
def test_delete_tokenset_by_id(self, mock_rc):
431+
mock_instance = mock_rc.return_value
432+
433+
u = Users(domain="domain", token="jwttoken")
434+
u.delete_tokenset_by_id("user_id", "tokenset_id")
435+
436+
mock_instance.delete.assert_called_with(
437+
"https://domain/api/v2/users/user_id/tokensets/tokenset_id"
438+
)

0 commit comments

Comments
 (0)