@@ -301,6 +301,10 @@ func (r *RootCmd) openApp() *serpent.Command {
301
301
pathAppURL := strings .TrimPrefix (region .PathAppURL , baseURL .String ())
302
302
appURL := buildAppLinkURL (baseURL , ws , agt , foundApp , region .WildcardHostname , pathAppURL )
303
303
304
+ if foundApp .External {
305
+ appURL = replacePlaceholderExternalSessionTokenString (client , appURL )
306
+ }
307
+
304
308
// Check if we're inside a workspace. Generally, we know
305
309
// that if we're inside a workspace, `open` can't be used.
306
310
insideAWorkspace := inv .Environ .Get ("CODER" ) == "true"
@@ -314,7 +318,7 @@ func (r *RootCmd) openApp() *serpent.Command {
314
318
if ! testOpenError {
315
319
err = open .Run (appURL )
316
320
} else {
317
- err = xerrors .New ("test.open-error" )
321
+ err = xerrors .New ("test.open-error: " + appURL )
318
322
}
319
323
return err
320
324
},
@@ -511,3 +515,15 @@ func buildAppLinkURL(baseURL *url.URL, workspace codersdk.Workspace, agent coder
511
515
}
512
516
return u .String ()
513
517
}
518
+
519
+ // replacePlaceholderExternalSessionTokenString replaces any $SESSION_TOKEN
520
+ // strings in the URL with the actual session token.
521
+ // This is consistent behaviour with the frontend. See: site/src/modules/resources/AppLink/AppLink.tsx
522
+ func replacePlaceholderExternalSessionTokenString (client * codersdk.Client , appURL string ) string {
523
+ if ! strings .Contains (appURL , "$SESSION_TOKEN" ) {
524
+ return appURL
525
+ }
526
+
527
+ // We will just re-use the existing session token we're already using.
528
+ return strings .ReplaceAll (appURL , "$SESSION_TOKEN" , client .SessionToken ())
529
+ }
0 commit comments