Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
2 changes: 2 additions & 0 deletions .gitleaksignore
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,5 @@ e7f5ad4253ad82236a5cff5f8c06878bfb190b00:tests/test_descope_client.py:jwt:185
e7f5ad4253ad82236a5cff5f8c06878bfb190b00:tests/test_descope_client.py:jwt:197
ece761372c78a9ad8a57da5f6d13431d298a99db:tests/test_auth.py:jwt:562
f3ec873c83a7067a1226d8b712b756b1b599fb3b:tests/test_descope_client.py:jwt:519
b6a2e217be5dceb6c85332d2e193619894d3a36e:README.md:generic-api-key:1349
b6a2e217be5dceb6c85332d2e193619894d3a36e:README.md:generic-api-key:1372
126 changes: 125 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ These sections show how to use the SDK to perform permission and user management
13. [Manage FGA (Fine-grained Authorization)](#manage-fga-fine-grained-authorization)
14. [Manage Project](#manage-project)
15. [Manage SSO Applications](#manage-sso-applications)
16. [Manage Outbound Applications](#manage-outbound-applications)

If you wish to run any of our code samples and play with them, check out our [Code Examples](#code-examples) section.

Expand Down Expand Up @@ -1178,7 +1179,7 @@ type doc
permission can_create: owner | parent.owner
permission can_edit: editor | can_create
permission can_view: viewer | can_edit
```
```

Descope SDK allows you to fully manage the schema and relations as well as perform simple (and not so simple) checks regarding the existence of relations.

Expand Down Expand Up @@ -1301,6 +1302,129 @@ apps = apps_resp["apps"]
# Do something
```

### Manage Outbound Applications

You can create, update, delete, load outbound applications and fetch tokens for them:

```python
# Create a basic outbound application
response = descope_client.mgmt.outbound_application.create_application(
name="my new app",
description="my desc",
client_secret="secret123", # Optional
id="my-custom-id", # Optional
)
app_id = response["app"]["id"]

# Create a full OAuth outbound application with all parameters
from descope.management.common import URLParam, AccessType, PromptType

# Create URL parameters for authorization
auth_params = [
URLParam("response_type", "code"),
URLParam("client_id", "my-client-id"),
URLParam("redirect_uri", "https://myapp.com/callback")
]

# Create URL parameters for token endpoint
token_params = [
URLParam("grant_type", "authorization_code"),
URLParam("client_id", "my-client-id")
]

# Create prompt types
prompts = [PromptType.LOGIN, PromptType.CONSENT]

full_app = descope_client.mgmt.outbound_application.create_application(
name="My OAuth App",
description="A full OAuth outbound application",
logo="https://example.com/logo.png",
id="my-custom-id", # Optional custom ID
client_secret="my-secret-key",
client_id="my-client-id",
discovery_url="https://accounts.google.com/.well-known/openid_configuration",
authorization_url="https://accounts.google.com/o/oauth2/v2/auth",
authorization_url_params=auth_params,
token_url="https://oauth2.googleapis.com/token",
token_url_params=token_params,
revocation_url="https://oauth2.googleapis.com/revoke",
default_scopes=["https://www.googleapis.com/auth/userinfo.profile"],
default_redirect_url="https://myapp.com/callback",
callback_domain="myapp.com",
pkce=True, # Enable PKCE
access_type=AccessType.OFFLINE, # Request refresh tokens
prompt=prompts
)

# Update an outbound application with all parameters
# Update will override all fields as is. Use carefully.
descope_client.mgmt.outbound_application.update_application(
id="my-app-id",
name="my updated app",
description="updated description",
logo="https://example.com/logo.png",
client_secret="new-secret", # Optional
client_id="new-client-id",
discovery_url="https://accounts.google.com/.well-known/openid_configuration",
authorization_url="https://accounts.google.com/o/oauth2/v2/auth",
authorization_url_params=auth_params,
token_url="https://oauth2.googleapis.com/token",
token_url_params=token_params,
revocation_url="https://oauth2.googleapis.com/revoke",
default_scopes=["https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/userinfo.email"],
default_redirect_url="https://myapp.com/updated-callback",
callback_domain="myapp.com",
pkce=True,
access_type=AccessType.OFFLINE,
prompt=[PromptType.LOGIN, PromptType.CONSENT, PromptType.SELECT_ACCOUNT]
)

# Delete an outbound application by id
# Outbound application deletion cannot be undone. Use carefully.
descope_client.mgmt.outbound_application.delete_application("my-app-id")

# Load an outbound application by id
app = descope_client.mgmt.outbound_application.load_application("my-app-id")

# Load all outbound applications
apps_resp = descope_client.mgmt.outbound_application.load_all_applications()
apps = apps_resp["apps"]
for app in apps:
# Do something with each app

# Fetch user token with specific scopes
user_token = descope_client.mgmt.outbound_application.fetch_token_by_scopes(
"my-app-id",
"user-id",
["read", "write"],
{"refreshToken": True}, # Optional
"tenant-id" # Optional
)

# Fetch latest user token
latest_user_token = descope_client.mgmt.outbound_application.fetch_token(
"my-app-id",
"user-id",
"tenant-id", # Optional
{"forceRefresh": True} # Optional
)

# Fetch tenant token with specific scopes
tenant_token = descope_client.mgmt.outbound_application.fetch_tenant_token_by_scopes(
"my-app-id",
"tenant-id",
["read", "write"],
{"refreshToken": True} # Optional
)

# Fetch latest tenant token
latest_tenant_token = descope_client.mgmt.outbound_application.fetch_tenant_token(
"my-app-id",
"tenant-id",
{"forceRefresh": True} # Optional
)
```

### Utils for your end to end (e2e) tests and integration tests

To ease your e2e tests, we exposed dedicated management methods,
Expand Down
48 changes: 46 additions & 2 deletions descope/management/common.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,32 @@
from typing import List, Optional
from typing import List, Optional, Dict, Any
from enum import Enum


class AccessType(Enum):
OFFLINE = "offline"
ONLINE = "online"


class PromptType(Enum):
NONE = "none"
LOGIN = "login"
CONSENT = "consent"
SELECT_ACCOUNT = "select_account"


class URLParam:
def __init__(self, name: str, value: str):
self.name = name
self.value = value

def to_dict(self) -> dict:
return {"name": self.name, "value": self.value}


def url_params_to_dict(url_params: Optional[List[URLParam]] = None) -> list:
if url_params is None:
return []

Check warning on line 28 in descope/management/common.py

View workflow job for this annotation

GitHub Actions / Coverage

This line has no coverage
return [param.to_dict() for param in url_params]


class MgmtV1:
Expand All @@ -19,6 +47,21 @@
sso_application_load_path = "/v1/mgmt/sso/idp/app/load"
sso_application_load_all_path = "/v1/mgmt/sso/idp/apps/load"

# outbound application
outbound_application_create_path = "/v1/mgmt/outbound/app/create"
outbound_application_update_path = "/v1/mgmt/outbound/app/update"
outbound_application_delete_path = "/v1/mgmt/outbound/app/delete"
outbound_application_load_path = "/v1/mgmt/outbound/app"
outbound_application_load_all_path = "/v1/mgmt/outbound/apps"
outbound_application_fetch_token_by_scopes_path = "/v1/mgmt/outbound/app/user/token"
outbound_application_fetch_token_path = "/v1/mgmt/outbound/app/user/token/latest"
outbound_application_fetch_tenant_token_by_scopes_path = (
"/v1/mgmt/outbound/app/tenant/token"
)
outbound_application_fetch_tenant_token_path = (
"/v1/mgmt/outbound/app/tenant/token/latest"
)

# user
user_create_path = "/v1/mgmt/user/create"
test_user_create_path = "/v1/mgmt/user/create/test"
Expand Down Expand Up @@ -365,7 +408,8 @@
)
return sort_list


def map_to_values_object(input_map: dict):
if not input_map:
return {}
return {k: {"values": v} for k, v in input_map.items()}
return {k: {"values": v} for k, v in input_map.items()}
Loading
Loading