Skip to content

Commit 0a65953

Browse files
authored
feature:FGI-1575 Add ability to manage a users connected accounts (#60)
* Add support for getting and deleting connected accounts * Linting fixes * Add some tests for new my account api methods * Add tests for server_client behaviour * Add some docs about managing connected accounts * Add doc comments * Claude review fixes * Claude doc fixes * Rename from_token to from_param * Add argument validation to new server_client methods * Add parameter validation to new my_account_api functions * Rename ListConnectedAccountResponse -> ListConnectedAccountsResponse * Restructure auth_types * Add doc comments to my account client * fix example domain in comment * Add error handling section to the docs
1 parent f4311d4 commit 0a65953

7 files changed

Lines changed: 1063 additions & 11 deletions

File tree

examples/ConnectedAccounts.md

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,129 @@ You can now call the API with your access token and the API can use [Access Toke
111111
```python
112112
access_token_for_google = await server_client.get_access_token_for_connection(
113113
{ "connection": "google-oauth2" },
114-
store_options=store_options
114+
store_options={"request": request, "response": response}
115+
)
116+
```
117+
118+
## Managing Connected Accounts
119+
120+
`ServerClient` exposes three methods for managing a user's connected accounts
121+
122+
### List Available Connections
123+
124+
This method provides a list of connections that have been enabled for use with Connected Accounts for Token Vault that the user may use to connect accounts.
125+
126+
This method requires the My Account `read:me:connected_accounts` scope to be enabled for your application and configured for MRRT.
127+
128+
This method supports paging via optional the use of `take` parameter. Without this parameters, a default page size of 10 is used. Subsequent pages can be retrieved by also passing the `from_param` parameter with the token returned in the `next` property of the response
129+
130+
```python
131+
available_connections = await client.list_connected_account_connections(
132+
take= 5, # optional
133+
from_param= "NEXT_VALUE_FROM_PREVIOUS_RESPONSE", # optional
134+
store_options= {"request": request, "response": response}
135+
)
136+
```
137+
138+
### List Connected Accounts
139+
140+
This method provides a list of accounts that you have already connected.
141+
142+
This method requires the My Account `read:me:connected_accounts` scope to be enabled for your application and configured for MRRT.
143+
144+
An optional `connection` parameter can be used to filter the connected accounts for a specific connection, otherwise all connected accounts will be returns
145+
146+
This method supports paging via optional the use of `take` parameter. Without this parameters, a default page size of 10 is used. Subsequent pages can be retrieved by also passing the `from_param` parameter with the token returned in the `next` property of the response
147+
148+
```python
149+
connected_accounts = await client.list_connected_accounts(
150+
connection= "google-oauth2", # optional
151+
take= 5, # optional
152+
from_param= "NEXT_VALUE_FROM_PREVIOUS_RESPONSE", # optional
153+
store_options= {"request": request, "response": response}
154+
)
155+
```
156+
157+
### Delete Connected Account
158+
159+
This method removes a connected account for the user.
160+
161+
This method requires the My Account `delete:me:connected_accounts` scope to be enabled for your application and configured for MRRT.
162+
163+
This method takes a `connected_account_id` parameter which can be obtained from `list_connected_accounts`.
164+
165+
```python
166+
connected_accounts = await client.delete_connected_account(
167+
connected_account_id= "CONNECTED_ACCOUNT_ID",
168+
store_options= {"request": request, "response": response}
169+
)
170+
```
171+
172+
## Error Handling
173+
174+
All SDK errors inherit from `Auth0Error`. For most cases, catch `Auth0Error` to handle all errors uniformly. Only catch specific error types when you need to take different actions based on the error.
175+
176+
### Basic Error Handling (Recommended)
177+
178+
```python
179+
from auth0_server_python.error import Auth0Error
180+
181+
try:
182+
connect_url = await client.start_connect_account(
183+
ConnectAccountOptions(connection="google-oauth2", redirect_uri="https://example.com/callback"),
184+
store_options={"request": request, "response": response}
185+
)
186+
except Auth0Error as e:
187+
print(f"Error: {str(e)}")
188+
return {"error": "Failed to connect account"}
189+
```
190+
191+
### Advanced Error Handling (When Specific Actions Required)
192+
193+
Catch specific types only when you need to handle different error conditions differently:
194+
195+
```python
196+
from auth0_server_python.error import Auth0Error, MyAccountApiError
197+
198+
try:
199+
connect_url = await client.start_connect_account(
200+
ConnectAccountOptions(connection="google-oauth2", redirect_uri="https://example.com/callback"),
201+
store_options={"request": request, "response": response}
202+
)
203+
except MyAccountApiError as e:
204+
if e.status == 401:
205+
return redirect_to_login() # Token expired
206+
elif e.status == 403:
207+
return {"error": "Missing required permission"} # Missing scope
208+
elif e.status == 400 and e.validation_errors:
209+
return {"error": "Validation failed", "details": e.validation_errors}
210+
raise # Re-raise other cases
211+
except Auth0Error as e:
212+
return {"error": str(e)}
213+
```
214+
215+
### Common Error Types
216+
217+
- **`Auth0Error`** (base): Catch this for general error handling
218+
- **`MyAccountApiError`**: My Account API errors with `status`, `detail`, and optional `validation_errors`
219+
- **`InvalidArgumentError`**: Invalid parameter value
220+
- **`MissingRequiredArgumentError`**: Required parameter not provided
221+
222+
## A note about scopes
223+
224+
If multiple pieces of Connected Account functionality are intended to be used, it is recommended that you set the default `scope` for the My Account audience when creating you `ServerClient`. This will avoid multiple token requests as without it a new token will be requested for each scope used. This can be done by configuring the `scope` dictionary in the `authorization_params` when configuring the SDK. Each value in the dictionary corresponds to an `audience` and sets the `default` requested scopes for that audience.
225+
226+
```python
227+
server_client = ServerClient(
228+
domain="YOUR_AUTH0_DOMAIN",
229+
client_id="YOUR_CLIENT_ID",
230+
client_secret="YOUR_CLIENT_SECRET",
231+
secret="YOUR_SECRET",
232+
authorization_params={
233+
"scope" {
234+
"https://YOUR_AUTH0_DOMAIN/me/": "create:me:connected_accounts read:me:connected_accounts delete:me:connected_accounts", # scopes required for the My Account audience
235+
# default scopes for custom API audiences can also be defined
236+
}
237+
}
115238
)
116239
```

0 commit comments

Comments
 (0)