Skip to content

Commit 3fb74bd

Browse files
committed
register, login, logout implemented with framework independence along with unit tests
1 parent 582d470 commit 3fb74bd

File tree

2 files changed

+99
-4
lines changed

2 files changed

+99
-4
lines changed

kinde_sdk/auth/oauth.py

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,4 +249,69 @@ def get_tokens_for_core(self, user_id: str) -> Optional[Dict[str, str]]:
249249
if refresh_token:
250250
tokens["refresh_token"] = refresh_token
251251

252-
return tokens
252+
return tokens
253+
254+
def register(self, state: Optional[str] = None, scope: Optional[List[str]] = None, audience: Optional[str] = None) -> str:
255+
"""
256+
Generate the registration URL for user sign-up.
257+
258+
Args:
259+
state (Optional[str]): A state parameter for CSRF protection.
260+
scope (Optional[List[str]]): A list of scopes to request.
261+
audience (Optional[str]): The audience for the token.
262+
263+
Returns:
264+
str: The registration URL.
265+
"""
266+
params = {
267+
"client_id": self.client_id,
268+
"response_type": "code",
269+
"redirect_uri": self.redirect_uri,
270+
"scope": " ".join(scope) if scope else "openid profile email", # Default scope
271+
"state": state or "",
272+
}
273+
if audience:
274+
params["audience"] = audience
275+
return f"{self.auth_url}/register?{urlencode(params)}"
276+
277+
278+
def login(self, state: Optional[str] = None, scope: Optional[List[str]] = None, audience: Optional[str] = None) -> str:
279+
"""
280+
Generate the login URL for user authentication.
281+
282+
Args:
283+
state (Optional[str]): A state parameter for CSRF protection.
284+
scope (Optional[List[str]]): A list of scopes to request.
285+
audience (Optional[str]): The audience for the token.
286+
287+
Returns:
288+
str: The login URL.
289+
"""
290+
params = {
291+
"client_id": self.client_id,
292+
"response_type": "code",
293+
"redirect_uri": self.redirect_uri,
294+
"scope": " ".join(scope) if scope else "openid profile email", # Default scope
295+
"state": state or "",
296+
}
297+
if audience:
298+
params["audience"] = audience
299+
return f"{self.auth_url}/login?{urlencode(params)}"
300+
301+
def logout(self, state: Optional[str] = None) -> str:
302+
"""
303+
Generate the logout URL.
304+
305+
Args:
306+
state (Optional[str]): A state parameter for CSRF protection.
307+
308+
Returns:
309+
str: The logout URL.
310+
"""
311+
params = {
312+
"client_id": self.client_id,
313+
"logout_uri": self.redirect_uri,
314+
}
315+
if state:
316+
params["state"] = state
317+
return f"{self.logout_url}?{urlencode(params)}"

testv2/testv2_auth/test_oauth.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,34 @@ def setUp(self):
1414
userinfo_url="https://example.com/userinfo" # Added userinfo_url
1515
)
1616

17+
def test_register(self):
18+
# Test the register method
19+
url = self.oauth.register(state="xyz", scope=["openid", "profile", "email"])
20+
parsed_url = urlparse(url)
21+
query_params = parse_qs(parsed_url.query)
22+
23+
self.assertEqual(parsed_url.scheme, "https")
24+
self.assertEqual(parsed_url.netloc, "example.com")
25+
self.assertEqual(parsed_url.path, "/auth/register")
26+
self.assertEqual(query_params["client_id"][0], "test_client_id")
27+
self.assertEqual(query_params["redirect_uri"][0], "http://localhost/callback")
28+
self.assertEqual(query_params["scope"][0], "openid profile email") # Expected scope
29+
self.assertEqual(query_params["state"][0], "xyz")
30+
31+
def test_login(self):
32+
# Test the login method
33+
url = self.oauth.login(state="xyz", scope=["openid", "profile", "email"])
34+
parsed_url = urlparse(url)
35+
query_params = parse_qs(parsed_url.query)
36+
37+
self.assertEqual(parsed_url.scheme, "https")
38+
self.assertEqual(parsed_url.netloc, "example.com")
39+
self.assertEqual(parsed_url.path, "/auth/login")
40+
self.assertEqual(query_params["client_id"][0], "test_client_id")
41+
self.assertEqual(query_params["redirect_uri"][0], "http://localhost/callback")
42+
self.assertEqual(query_params["scope"][0], "openid profile email") # Expected scope
43+
self.assertEqual(query_params["state"][0], "xyz")
44+
1745
def test_get_login_url(self):
1846
# Explicitly specify the scope
1947
url = self.oauth.get_login_url(state="xyz", scope=["openid", "profile", "email"])
@@ -57,7 +85,8 @@ def test_get_tokens_for_core(self):
5785
self.assertEqual(tokens["refresh_token"], "test_refresh_token")
5886

5987
def test_logout(self):
60-
logout_url = self.oauth.logout("test_user_id")
88+
# Test the logout method
89+
logout_url = self.oauth.logout(state="xyz")
6190
parsed_url = urlparse(logout_url)
6291
query_params = parse_qs(parsed_url.query)
6392

@@ -66,6 +95,7 @@ def test_logout(self):
6695
self.assertEqual(parsed_url.path, "/logout")
6796
self.assertEqual(query_params["client_id"][0], "test_client_id")
6897
self.assertEqual(query_params["logout_uri"][0], "http://localhost/callback")
98+
self.assertEqual(query_params["state"][0], "xyz")
6999

70-
if __name__ == "__main__":
71-
unittest.main()
100+
# if __name__ == "_main_":
101+
#  unittest.main()

0 commit comments

Comments
 (0)