Hi everyone, I'd like to discuss some authorizati...
# opal
t
Hi everyone, I'd like to discuss some authorization challenges we’ve been facing with OPAL External Data Source and get some feedback and experiences from the community. In our setup, every time we call the Triggering Data Updates API, we include a data source token in the payload entries that gets pushed to subscribers. The OPAL Client then uses this token to fetch data. Currently, under secure mode, the OPAL_CLIENT_TOKEN (JWT) is only validated at two points: • When initially establishing the WebSocket connection (handshake) • When reconnecting after a disconnect Once the connection is successfully established, the WebSocket connection continues to receive all topic updates even if the client token has expired. A hypothetical concern is that if an attacker obtains a client token, they could continuously access all the latest triggered data as long as the WebSocket connection remains open. Setting a short expiration for the client token seems ineffective and could cause issues with normal disconnects and reconnects, impacting availability. Similarly, setting a short expiration for the data source token also doesn't help because a new token is sent with every Trigger Data Updates call. I’m curious if the community has any strategic recommendations for managing authorization between OPAL client and server? Or if anyone knows of a way for the client to automatically include its OPAL Client Token during data fetch, so the Data Source could verify the token again on its end. Thanks!
a
Hi @Tony Ou, I'm an AI assistant for Permit.io. I'll analyze available sources and get back to you shortly.
This is a valid security concern regarding OPAL's authentication model. Based on the documentation, here's what I can share about OPAL's current approach and potential solutions: Current OPAL Authentication Model When using external data sources with OPAL, the server can redirect queries to external APIs while passing the OPAL client JWT as a query parameter (1) . The external API receives requests in this format:
Copy code
<https://your-api.com/path/to/api/endpoint?token=<OPAL_CLIENT_JWT>>
The external API should then extract and validate this JWT using the OPAL public key . Implementing Additional Verification For your data source to verify the OPAL client token, you can implement validation similar to this Python example :
Copy code
from opal_common.schemas.security import AccessTokenRequest, PeerType  
from acalla.config import OPAL_SERVER_URL, OPAL_MASTER_TOKEN  
  
...  
  
async with aiohttp.ClientSession(headers={"Authorization": f"bearer {OPAL_MASTER_TOKEN}", **self._headers}) as session:  
 token_params = AccessTokenRequest(  
 type=PeerType.client,  
 ttl=timedelta(days=CLIENT_TOKEN_TTL_IN_DAYS) ,  
 claims={'permit_client_id': pdp.client_id},  
 ) .json()  
async with <http://session.post|session.post>(f"{OPAL_SERVER_URL}/token", data=token_params) as response:  
 data: dict = await response.json()  
 token = data.get("token", None)
Configuration Options You can configure token behavior using these environment variables (2) : •
OPAL_CLIENT_TOKEN
- The authentication token for the client •
OPAL_AUTH_JWT_AUDIENCE
- Expected audience in JWT tokens •
OPAL_AUTH_JWT_ISSUER
- Expected issuer in JWT tokens Recommendations 1. ​*Use Custom Claims*​: Add identifying claims to client tokens that your data source can verify (1) 2. ​*External Validation*​: Configure your external data source to validate the OPAL client JWT on each fetch request 3. ​*HTTPS Only*​: Never use non-HTTPS URLs for
external_source_url
to protect the JWT in transit The WebSocket persistence issue you describe is a known architectural consideration. While the documentation doesn't provide a built-in solution for continuous token validation during an active WebSocket connection, implementing validation at the data source level provides an additional security layer.
To learn more, see the sources I considered: [[1] How to configure external data sources](https://docs.opal.ac/tutorials/configure_external_data_sources) [[2] OPAL Configuration Guide | OPAL](https://docs.opal.ac/getting-started/configuration)
o
Data sources are meant to share data needed by the policy-engine to make policy decisions, not propagating secrets. I wouldn't recommend this approach. I'd recommend loading secrets via secret management solutions (e.g. secrets in kubernetes, or as part of your CI/CD system)
t
HI @Or Weis , thanks for the clarification. I agree that OPAL is not intended for distributing secrets, and we are already passing the OPAL Client Token via Kubernetes Secrets. My question is more focused on the authorization model: Even when the OPAL Client Token (JWT) expires, an already-established WebSocket connection continues to receive policy data updates without re-validation. Do you consider this a potential security risk in production environments? Are there recommended best practices to mitigate this? Additionally, I was wondering whether the OPAL client could optionally include its OPAL Client Token during data fetch requests, so that the Data Source server could perform an additional layer of validation. Do you have any suggestions or recommended patterns? Thanks again!
p
Hey, thanks for reaching out ! It seems our team is a little busy right now, a human will be with you within the next hour or so. In the meantime, can I help you ?
a
Hey @Tony Ou, Thanks for following up, I’ll let @Ask Inkeep try to answer this
a
Thanks for tagging me @Alon Boshi. I'll look through relevant sources and get back to you shortly.
The WebSocket connection behavior you describe is indeed how OPAL's architecture currently works. OPAL uses outgoing websocket connections to establish a Pub/Sub channel, and these connections are designed to stay idle most of the time to save CPU cycles (1) . The clients open an outgoing websocket connection to servers, creating a bi-directional Pub/Sub channel (2) . For triggering data updates with authentication, OPAL requires a datasource identity token (JWT) for services that publish updates (3) . You can obtain this token using:
Copy code
opal-client obtain-token $OPAL_AUTH_MASTER_TOKEN --server-url=$YOUR_SERVERS_ADDRESS --type datasource
Or via REST API:
Copy code
curl --request POST '<https://opal.yourdomain.com/token>' \
--header 'Authorization: Bearer MY_MASTER_TOKEN' \
--header 'Content-Type: application/json' \
--data-raw '{
 "type": "datasource",
}'
When publishing data updates, you can include authentication credentials that will be passed to the data source :
Copy code
opal-client publish-data-update $token --src-url <http://mybillingserver.com/users> -t users -t billing --src-config '{"headers":{"authorization":"bearer secret-token"}}'
This allows the data source itself to validate the credentials when OPAL clients fetch data. The architecture separates the Pub/Sub channel authentication from the data fetching authentication, which addresses part of your concern by enabling validation at the data source level.
To learn more, see the sources I considered: [[1] Design](https://docs.opal.ac/overview/design) [[2] Architecture 🏗️](https://docs.opal.ac/overview/architecture) [[3] Triggering Data Updates](https://docs.opal.ac/tutorials/trigger_data_updates)
o
I wouldn't consider a long-lived (by definition) connection surviving its token expiry an issue. The token is a credential to establish a connection not a connection management solution. You'd be hard-pressed to find any system in which long-lived connections are governed by token expiry dates. You'd also note that OPAL's architecture decouples events and actual data, so access to OPAL updates doesn't actually provide any data, unless you abuse it and send secrets like you suggested for example.
I might be failing to see some underlying problem or issue you're concerned with. If so, feel free to try and explain that issue more directly.