🐛 Bug Report: No "Add Another" button for Callback URLs when editing OIDC that was once edited via API #250

Closed
opened 2025-10-07 23:59:12 +03:00 by OVERLORD · 1 comment
Owner

Originally created by @TerrifiedBug on GitHub.

Bug: Unable to add additional callback URLs to API-created OIDC Client via GUI

Reproduction steps

  1. Create an OIDC Client with multiple callback URLs using the API
  2. Try to edit this OIDC Client through the GUI
  3. Attempt to add additional callback URLs via the GUI interface

When editing an OIDC Client created via API in the GUI, it's not possible to add any more callback URLs. The client currently has 54 callback URLs configured.

Editing API-created OIDC:
API Created OIDC Client

Editing UI-created OIDC for comparison:
UI Created OIDC Client

Code used to create the OIDC Client

payload = {
    "callbackURLs": CALLBACK_URLS,
    "name": CLIENT_NAME,
    "isPublic": False,
    "pkceEnabled": False,
}
update_response = requests.put(
    f"{POCKETID_BASE_URL}/api/oidc/clients/{client_id}",
    headers=HEADERS,
    json=payload,
    timeout=60,
)

Expected behavior

When editing an OIDC Client created via API within the GUI, users should be able to add additional callback URLs just like with clients created through the UI.

Actual Behavior

When editing an OIDC Client created via API within the GUI, users are unable to add additional callback URLs. The interface appears different from UI-created clients and doesn't provide the option to add more URLs.

Version and Environment

Version: 0.48.0

Log Output

No response

Additional Information

The full script used to create the OIDC Client is included below:

"""Script to update callback URLs for OIDC client en masse. OIDC Needs to exist before hand"""
import requests

DOMAIN = "domain.com"
CLIENT_NAME = "your-oidc-client-name-here"
API_KEY = "your-api-key-here"
POCKETID_BASE_URL = "https://your-pocketid-url-here"
HEADERS = {
    "Content-Type": "application/json",
    "Accept": "application/json",
    "X-API-KEY": API_KEY,
}

def load_services():
    """Load services from services.txt file."""
    try:
        with open("services.txt", "r", encoding="utf-8") as file:
            return [line.strip() for line in file if line.strip()]
    except FileNotFoundError:
        print("Error: services.txt file not found")
        exit(1)

SERVICES = load_services()
CALLBACK_URLS = [
    f"https://{service}.{DOMAIN}/caddy-security/oauth2/generic/authorization-code-callback"
    for service in SERVICES
]

def main():
    """Main function to get and update client information."""
    response = requests.get(
        f"{POCKETID_BASE_URL}/api/oidc/clients",
        headers=HEADERS,
        timeout=60
    )
    print(f"Status: {response.status_code}")
    try:
        response_data = response.json()
        if "data" in response_data and isinstance(response_data["data"], list):
            clients = response_data["data"]
        else:
            print(f"Unexpected API response structure: {response_data}")
            exit(1)

        client_id = None
        for client in clients:
            if client.get("name") == CLIENT_NAME:
                client_id = client.get("id")
                break

        if not client_id:
            print(f"Could not find a client named '{CLIENT_NAME}'")
            exit(1)

        print(f"Found client '{CLIENT_NAME}' with ID: {client_id}")

        payload = {
            "callbackURLs": CALLBACK_URLS,
            "name": CLIENT_NAME,
            "isPublic": False,
            "pkceEnabled": False,
        }
        update_response = requests.put(
            f"{POCKETID_BASE_URL}/api/oidc/clients/{client_id}",
            headers=HEADERS,
            json=payload,
            timeout=60,
        )
        print(f"Update Status: {update_response.status_code}")
        print(update_response.text)
    except requests.exceptions.JSONDecodeError:
        print("Failed to parse JSON response")
        exit(1)
    except requests.exceptions.RequestException as e:
        print(f"Request error: {e}")
        exit(1)

if __name__ == "__main__":
    main()
Originally created by @TerrifiedBug on GitHub. ### Bug: Unable to add additional callback URLs to API-created OIDC Client via GUI #### Reproduction steps 1. Create an OIDC Client with multiple callback URLs using the API 2. Try to edit this OIDC Client through the GUI 3. Attempt to add additional callback URLs via the GUI interface When editing an OIDC Client created via API in the GUI, it's not possible to add any more callback URLs. The client currently has 54 callback URLs configured. **Editing API-created OIDC:** ![API Created OIDC Client](https://github.com/user-attachments/assets/49abf2d9-98d3-4473-90b2-2e5f5108a96b) **Editing UI-created OIDC for comparison:** ![UI Created OIDC Client](https://github.com/user-attachments/assets/c14d9568-7a4a-4744-916b-808964014800) #### Code used to create the OIDC Client ```python payload = { "callbackURLs": CALLBACK_URLS, "name": CLIENT_NAME, "isPublic": False, "pkceEnabled": False, } update_response = requests.put( f"{POCKETID_BASE_URL}/api/oidc/clients/{client_id}", headers=HEADERS, json=payload, timeout=60, ) ``` #### Expected behavior When editing an OIDC Client created via API within the GUI, users should be able to add additional callback URLs just like with clients created through the UI. #### Actual Behavior When editing an OIDC Client created via API within the GUI, users are unable to add additional callback URLs. The interface appears different from UI-created clients and doesn't provide the option to add more URLs. #### Version and Environment Version: 0.48.0 #### Log Output *No response* #### Additional Information The full script used to create the OIDC Client is included below: ```python """Script to update callback URLs for OIDC client en masse. OIDC Needs to exist before hand""" import requests DOMAIN = "domain.com" CLIENT_NAME = "your-oidc-client-name-here" API_KEY = "your-api-key-here" POCKETID_BASE_URL = "https://your-pocketid-url-here" HEADERS = { "Content-Type": "application/json", "Accept": "application/json", "X-API-KEY": API_KEY, } def load_services(): """Load services from services.txt file.""" try: with open("services.txt", "r", encoding="utf-8") as file: return [line.strip() for line in file if line.strip()] except FileNotFoundError: print("Error: services.txt file not found") exit(1) SERVICES = load_services() CALLBACK_URLS = [ f"https://{service}.{DOMAIN}/caddy-security/oauth2/generic/authorization-code-callback" for service in SERVICES ] def main(): """Main function to get and update client information.""" response = requests.get( f"{POCKETID_BASE_URL}/api/oidc/clients", headers=HEADERS, timeout=60 ) print(f"Status: {response.status_code}") try: response_data = response.json() if "data" in response_data and isinstance(response_data["data"], list): clients = response_data["data"] else: print(f"Unexpected API response structure: {response_data}") exit(1) client_id = None for client in clients: if client.get("name") == CLIENT_NAME: client_id = client.get("id") break if not client_id: print(f"Could not find a client named '{CLIENT_NAME}'") exit(1) print(f"Found client '{CLIENT_NAME}' with ID: {client_id}") payload = { "callbackURLs": CALLBACK_URLS, "name": CLIENT_NAME, "isPublic": False, "pkceEnabled": False, } update_response = requests.put( f"{POCKETID_BASE_URL}/api/oidc/clients/{client_id}", headers=HEADERS, json=payload, timeout=60, ) print(f"Update Status: {update_response.status_code}") print(update_response.text) except requests.exceptions.JSONDecodeError: print("Failed to parse JSON response") exit(1) except requests.exceptions.RequestException as e: print(f"Request error: {e}") exit(1) if __name__ == "__main__": main() ```
OVERLORD added the bug label 2025-10-07 23:59:12 +03:00
Author
Owner

@stonith404 commented on GitHub:

The limit has been removed in c37a3e0ed1 and will be included in the next release.

@stonith404 commented on GitHub: The limit has been removed in c37a3e0ed177c3bd2b9a618d1f4b0709004478b0 and will be included in the next release.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/pocket-id-pocket-id-1#250