Want to start by saying thanks for taking the time to provide all the great feedback and acknowledge the importance of getting the design right for Forge Remote offline access whilst balancing a number of complex competing concerns.
Hopefully, I can provide some more detail on some of the thinking behind this RFC and address some of the concerns raised so far.
Complexity
It has been raised a few times that the authTrigger URL invocations would be made async and therefore add complexity to the remote server implementation.
This was not the intention. Calls to the remote endpoint URL associated to the authTrigger would be made synchronously from the Forge Platform. The benefit of this is that you should be able to develop your remote auth server in a way that appears like a standard token fetch, only invoking the authTriggerUrl refresh flow in the case where you no longer have a valid token or it has since expired.
Example sequence diagram showing how this could look
Example Java Code showing how this might be implemented at a high level:
public String getToken(final String installationId) {
final Optional<Token> storedToken = tokenStore.findById(installationId);
if (storedToken.isPresent()) {
log.info("Cache Hit: Found token in store for installationId={}", installationId);
return decryptToken(storedToken.get().getEncryptedToken());
}
log.info("Cache Miss: Looking up authTrigger url for installationId={}", installationId);
final Optional<Installation> installationStoreById = installationStore.findById(installationId);
if (installationStoreById.isPresent()) {
final String authTriggerUrl = installationStoreById.get().getAuthTriggerUrl();
final String appId = installationStoreById.get().getAppId();
final ResponseEntity<Void> responseEntity = webClient.get()
.uri(authTriggerUrl)
.retrieve()
.toEntity(Void.class)
.block();
if (requireNonNull(responseEntity).getStatusCode().is2xxSuccessful()) {
return getTokenFromStore(installationId).orElseThrow();
} else {
throw new RuntimeException("Unable to fetch token authTriggerUrl returned status code " + responseEntity.getStatusCode());
}
}
log.error("No authTrigger url stored for installationId={}", installationId);
throw new RuntimeException("Unable to fetch token no authTriggerUrl stored for installationId " + installationId);
}
Standards Compliance
As mentioned a key goal for Forge Remote is to adhere to existing standards as much as possible.
That being said we also need to achieve the following Security Controls:
- Time limited access credentials
- Tenant Isolated access credentials
- Policy enforcement checks at point of credential refresh
In order to achieve tenant isolation and allow Remote Access to hosted storage for example we need to ensure that any access tokens provided are isolated to a given app installation. This negates the ability to use a standard OAuth client credentials grant flow with credentials per app.
