Customer feature parity: no token fetch when matching serverless content permits usage#10
Conversation
There was a problem hiding this comment.
Pull request overview
Adds customer-side feature parity for “serverless usage grants” so callers can avoid fetching a license token when a matching <content> block (without server) explicitly permits the requested usage, while also improving caching behavior around license.xml and token reuse.
Changes:
- Introduce
UsageTypeand extendobtain_license_token(..., usage=...)to returnNonewhen a matching serverless usage grant allows the request. - Cache
license.xmlper origin (TTL) and cache license tokens by matched pattern + token server to reuse across matching URLs. - Update content parsing and tests to treat serverless
<content>blocks as valid (for usage grants).
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
connect/customer/token.py |
Adds usage-based serverless bypass, license.xml caching, and updates token cache keying. |
connect/customer/content_parser.py |
Allows parsing <content> blocks without server and normalizes license_xml output. |
connect/types.py |
Introduces UsageType enum. |
connect/customer/__init__.py |
Re-exports UsageType alongside obtain_license_token. |
connect/__init__.py |
Exposes UsageType at the package top-level API. |
tests/customer/test_tokens.py |
Adds coverage for license.xml caching, token caching by matched pattern, and serverless usage-grant behavior. |
tests/customer/test_content_parser.py |
Updates parsing expectations and adds serverless-content test. |
tests/customer/conftest.py |
Clears the new license.xml cache between tests. |
examples/obtain_and_verify_license_token.py |
Adds a runtime guard for obtain_license_token now returning None. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| cache_key = (client_id, matched_content.server, matched_content.url_pattern) | ||
| cached = _get_cached_token(cache_key, debug) | ||
| if cached is not None: |
There was a problem hiding this comment.
The token cache key no longer includes the resource origin (it’s now keyed by client_id + token server + matched url_pattern). For path-only patterns like "/" or "/articles/", this can collide across different origins and return a token minted for a different license.xml/resource set. Consider including the resource origin (or a stable identifier like the license.xml URL / a hash of the matched license XML) in the cache key to prevent cross-origin token reuse.
There was a problem hiding this comment.
This is something for us to take into account when we think of generalizing to not only Supertab Connect. Our server URL is already unique per website's base URL
| if _local_name(element.tag) == "permits" and element.attrib.get("type") == "usage": | ||
| permitted_usages = " ".join(element.itertext()).split() | ||
| if UsageType.ALL in permitted_usages or usage_value in permitted_usages: | ||
| return True |
There was a problem hiding this comment.
question: There is twice the same for loop. Do you think we can do it in one go?
There was a problem hiding this comment.
I didn't see an immediate simplification (or complication, depends on how you look at it :P) yesterday so I considered this to be okay, but apparently it is possible!
Python's version of getsupertab/connect-sdk-typescript#29