Hi,
for one of our apps, we (want to) use an on behalf token flow to authenticate the user with a database. [See the config / code snippets below for details.]
For this purpose, we pass the ID token received from our Azure AD app to the app and request an access token via the on behalf token flow using the provided ID token. This all works fine when launching the app within the validity timeframe of the ID token (one hour in our case) - but if one launches the app after this validity timeframe, ShinyProxy does not renew the ID token before it passes it to the app thus, the on behalf token flow is failing with:
<http_400 in process_aad_response(res): Bad Request (HTTP 400). Failed to obtain Azure Active Directory token. Message:
AADSTS500133: Assertion is not within its valid time range. Ensure that the access token is not expired before using it for user assertion, or request a new token. Current time: 2024-01-11T08:45:09.3231723Z, expiry time of assertion 2024-01-11T07:53:07.0000000Z. Trace ID: xxx Correlation ID: xxx Timestamp: 2024-01-11 08:45:09Z.>
To be able to use the app again, the user must do a logout / login dance.
We also tried to use the refresh token to refresh the ID token before we initiate the on behalf token flow, but as we only get back an unsigned ID token, we can’t use it for the on behalf token flow.
Are we doing something wrong? Is that expected behavior or might that be a bug in ShinyProxy?
Best regards
Philip
application.yml
spring:
session:
store-type: redis
redis:
host: 127.0.0.1
password: *
proxy:
title: ShinyProxy DEV
bind-address: 127.0.0.1
port: 8080
favicon-path: /etc/shinyproxy/favicon-32x32.png
template-path: /etc/shinyproxy/templates
hide-navbar: true
authentication: openid
openid:
auth-url: https://login.microsoftonline.com/<tenant>/oauth2/authorize
token-url: https://login.microsoftonline.com/<tenant>/oauth2/token
jwks-url: https://login.microsoftonline.com/common/discovery/keys
logout-url: /logout-success
client-id: *
client-secret: *
username-attribute: name
scopes: ["https://database.windows.net/user_impersonation", "offline_access"]
default-webSocket-reconnection-mode: Auto
default-proxy-max-lifetime: 1440
store-mode: Redis
stop-proxies-on-shutdown: false
specs:
- id: odbc-sso_test
display-name: ODBC test app
container-image: odbc-sso_test
container-env:
SHINYPROXY_ID_TOKEN: "#{oidcUser.idToken.tokenValue}"
SHINYPROXY_REFRESH_TOKEN: "#{oidcUser.refreshToken}"
APP_ID: "*"
TENANT: "*"
CSECRET: "*"
R code:
.dbToken <- tryCatch(AzureAuth::get_azure_token("https://database.windows.net",
tenant = Sys.getenv("TENANT"),
app = Sys.getenv("APP_ID"),
password = Sys.getenv("CSECRET"),
use_cache = TRUE,
on_behalf_of = Sys.getenv("SHINYPROXY_ID_TOKEN")
), error = function(e) {
print(e)
})
if (AzureAuth::is_azure_token(.dbToken)) {
ch <- odbc::dbConnect(odbc::odbc(),
DSN = DSN,
database = database,
Authentication = "",
Encrypt = "yes",
attributes = list("azure_token" = AzureAuth::extract_jwt(.dbToken, type = "access"))
)
}