@@ -475,12 +475,20 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
475475t .Run ("CORS" ,func (t * testing.T ) {
476476t .Parallel ()
477477
478- t .Run ("AuthenticatedPassthruProtected" ,func (t * testing.T ) {
478+ // Set up test headers that should be returned by the app
479+ testHeaders := http.Header {
480+ "Access-Control-Allow-Origin" : []string {"*" },
481+ "Access-Control-Allow-Methods" : []string {"GET, POST, OPTIONS" },
482+ }
483+
484+ t .Run ("UnauthenticatedPassthruRejected" ,func (t * testing.T ) {
479485t .Parallel ()
480486
481487ctx := testutil .Context (t ,testutil .WaitLong )
482488
483- appDetails := setupProxyTest (t ,nil )
489+ appDetails := setupProxyTest (t ,& DeploymentOptions {
490+ headers :testHeaders ,
491+ })
484492
485493// Given: an unauthenticated client
486494client := appDetails .AppClient (t )
@@ -491,7 +499,7 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
491499require .NoError (t ,err )
492500defer resp .Body .Close ()
493501
494- // Then: the request is redirected tothe primary access URL because even though CORS is passthru,
502+ // Then: the request is redirected tologin because even though CORS is passthru,
495503// the request must still be authenticated first
496504require .Equal (t ,http .StatusSeeOther ,resp .StatusCode )
497505gotLocation ,err := resp .Location ()
@@ -505,7 +513,9 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
505513
506514ctx := testutil .Context (t ,testutil .WaitLong )
507515
508- appDetails := setupProxyTest (t ,nil )
516+ appDetails := setupProxyTest (t ,& DeploymentOptions {
517+ headers :testHeaders ,
518+ })
509519
510520userClient ,_ := coderdtest .CreateAnotherUser (t ,appDetails .SDKClient ,appDetails .FirstUser .OrganizationID ,rbac .RoleMember ())
511521userAppClient := appDetails .AppClient (t )
@@ -516,6 +526,65 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
516526require .NoError (t ,err )
517527defer resp .Body .Close ()
518528require .Equal (t ,http .StatusOK ,resp .StatusCode )
529+
530+ // Check CORS headers are passed through
531+ require .Equal (t ,testHeaders .Get ("Access-Control-Allow-Origin" ),resp .Header .Get ("Access-Control-Allow-Origin" ))
532+ require .Equal (t ,testHeaders .Get ("Access-Control-Allow-Credentials" ),resp .Header .Get ("Access-Control-Allow-Credentials" ))
533+ require .Equal (t ,testHeaders .Get ("Access-Control-Allow-Methods" ),resp .Header .Get ("Access-Control-Allow-Methods" ))
534+ })
535+
536+ t .Run ("UnauthenticatedPublicPassthruOK" ,func (t * testing.T ) {
537+ t .Parallel ()
538+
539+ ctx := testutil .Context (t ,testutil .WaitLong )
540+
541+ appDetails := setupProxyTest (t ,& DeploymentOptions {
542+ headers :testHeaders ,
543+ })
544+
545+ // Given: an unauthenticated client
546+ client := appDetails .AppClient (t )
547+ client .SetSessionToken ("" )
548+
549+ // When: a request is made to a public app with passthru CORS behavior
550+ resp ,err := requestWithRetries (ctx ,t ,client ,http .MethodGet ,appDetails .SubdomainAppURL (appDetails .Apps .PublicCORSPassthru ).String (),nil )
551+ require .NoError (t ,err )
552+ defer resp .Body .Close ()
553+
554+ // Then: the request succeeds because the app is public
555+ require .Equal (t ,http .StatusOK ,resp .StatusCode )
556+
557+ // Check CORS headers are passed through
558+ require .Equal (t ,testHeaders .Get ("Access-Control-Allow-Origin" ),resp .Header .Get ("Access-Control-Allow-Origin" ))
559+ require .Equal (t ,testHeaders .Get ("Access-Control-Allow-Credentials" ),resp .Header .Get ("Access-Control-Allow-Credentials" ))
560+ require .Equal (t ,testHeaders .Get ("Access-Control-Allow-Methods" ),resp .Header .Get ("Access-Control-Allow-Methods" ))
561+ })
562+
563+ t .Run ("AuthenticatedPublicPassthruOK" ,func (t * testing.T ) {
564+ t .Parallel ()
565+
566+ ctx := testutil .Context (t ,testutil .WaitLong )
567+
568+ appDetails := setupProxyTest (t ,& DeploymentOptions {
569+ headers :testHeaders ,
570+ })
571+
572+ userClient ,_ := coderdtest .CreateAnotherUser (t ,appDetails .SDKClient ,appDetails .FirstUser .OrganizationID ,rbac .RoleMember ())
573+ userAppClient := appDetails .AppClient (t )
574+ userAppClient .SetSessionToken (userClient .SessionToken ())
575+
576+ // Given: an authenticated client accessing a public app with passthru CORS behavior
577+ resp ,err := requestWithRetries (ctx ,t ,userAppClient ,http .MethodGet ,appDetails .SubdomainAppURL (appDetails .Apps .PublicCORSPassthru ).String (),nil )
578+ require .NoError (t ,err )
579+ defer resp .Body .Close ()
580+
581+ // Then: the request succeeds because the app is public
582+ require .Equal (t ,http .StatusOK ,resp .StatusCode )
583+
584+ // Check CORS headers are passed through
585+ require .Equal (t ,testHeaders .Get ("Access-Control-Allow-Origin" ),resp .Header .Get ("Access-Control-Allow-Origin" ))
586+ require .Equal (t ,testHeaders .Get ("Access-Control-Allow-Credentials" ),resp .Header .Get ("Access-Control-Allow-Credentials" ))
587+ require .Equal (t ,testHeaders .Get ("Access-Control-Allow-Methods" ),resp .Header .Get ("Access-Control-Allow-Methods" ))
519588})
520589})
521590
@@ -1842,7 +1911,7 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
18421911})
18431912
18441913// See above test for original implementation.
1845- t .Run ("CORSHeadersConditionalStrip " ,func (t * testing.T ) {
1914+ t .Run ("CORSHeadersConditionallyStripped " ,func (t * testing.T ) {
18461915t .Parallel ()
18471916
18481917// Set a bunch of headers which may or may not be stripped, depending on the CORS behavior.
@@ -1854,15 +1923,6 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
18541923"Access-Control-Allow-Credentials" : []string {"true" },
18551924"Access-Control-Allow-Methods" : []string {"PUT" },
18561925"Access-Control-Allow-Headers" : []string {"X-Foobar" },
1857- "Vary" : []string {
1858- "Origin" ,
1859- "origin" ,
1860- "Access-Control-Request-Headers" ,
1861- "access-Control-request-Headers" ,
1862- "Access-Control-Request-Methods" ,
1863- "ACCESS-CONTROL-REQUEST-METHODS" ,
1864- "X-Foobar" ,
1865- },
18661926}
18671927
18681928appDetails := setupProxyTest (t ,& DeploymentOptions {