HowTo: Creating a Failure Page for Post-Auth EPA

This post is a little bit niche as it may be relevant only for basic EPA expressions done on Citrix Gateway session policies whose use is slowly reducing, but figured it was worth covering off as there is still use cases for using EPA expressions in a session policy.

What I cover in this article is a somewhat elaborate method of providing a user-friendly EPA failure page in scenarios where we must use EPA in session policies, and cannot allow entry to users who fail the EPA scan.

A little visual below of our end result (note the text does not align to the sample provided below, this is just a general reference).


When running EPA in session policy expressions, we need to ensure bound policies have a matching expression for both pass or fail scenarios otherwise a user who fails the EPA check will default to the global Citrix Gateway session policy configs (that lovely white page talking about Java screen). In my experience configuring EPA in session profiles (vs policy expression) gets ignored in current builds of 12.1.

If this was a pre-auth scan or an EPA factor in nFactor, failing the EPA scan without a recourse (cascade or quarantine) will display a nice error message for users from EPA, which we could enhance with verbose EPA logging. However this isn’t an option in some cases, and we get the experience noted above.


I will cover implementing this as a “catch-all” session policy but in reality, the configs could be modified on the global Citrix Gateway session policy configs, but I largely prefer to leave those settings untouched.

It involves creating an HTML error page hosted on the ADC (using a cool obscure feature of the responder engine that allows for storing HTML code) and linking that to an APIPA LBVS that is always up to which we link a responder policy that renders the HTML page. We reference this LBVS in a session profile as a homepage and are sure to set the default authorization action to “DENY” in this profile. This profile gets referenced by a session policy with the lowest priority and a catch-all “true” value.

Step 1: Creating the Dummy vServer

These commands will great an LBVS that is always online, to which we can bind a responder policy. It uses a non-addressable IP that the ADC can access, but will not be accessible on the network, which is just fine.

add service svc_alwaysup HTTP 80
add lb vserver lbvs_epadeny_80 HTTP 80 -persistenceType NONE
bind lb vserver lbvs_epadeny_80 svc_alwaysup

Step 2: Creating the Responder Configuration

Let’s create our responder HTML page import via AppExpert>Responder>HTML Page Imports. This isn’t easily done via CLI and in fact, this does not even show up in the ns.conf file so screenshots are below. Instead of this, you could totally have a website created just to act as a landing page for failed users that is not hosted by the ADC and just redirect users there, but it is more fun to keep it internal to the ADC. But really, whatever works best for you.

For the HTML text, we’re using the following, which you can tweak to your heart’s content or merely use as a concept to develop something entirely different. Just remember to keep it basic and any images should be referenced as links from another site (perhaps a logo file from a public website, or image already found on the ADC from a portal theme).

<!DOCTYPE html>
                <html lang="en">
                    <!-- Simple HttpErrorPages | MIT License | -->
                    <meta charset="utf-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1" />
                    <title>Citrix EPA Scan Failed - Access Denied</title>
                    <style type="text/css">/*! normalize.css v5.0.0 | MIT License | */html{font-family:"citrixsans","HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:"citrixsans","HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:"citrixsans","HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:"citrixsans","HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none}/*! Simple HttpErrorPages | MIT X11 License | */body,html{width:100%;height:100%;background-color:#000}body{color:rgb(255, 255, 255);text-align:center;text-shadow:0 2px 4px rgba(0,0,0,.5);padding:0;min-height:100%;-webkit-box-shadow:inset 0 0 100px rgba(0,0,0,.8);box-shadow:inset 0 0 100px rgba(0,0,0,.8);display:table;font-family:"citrixsans","HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif}h1{font-family:inherit;font-weight:500;line-height:1.1;color:inherit;font-size:26px}h1 small{font-size:68%;font-weight:400;line-height:1;color:#777}a{text-decoration:none;color:#fff;font-size:inherit;border-bottom:dotted 1px #707070}.lead{color:rgb(255, 255, 255);font-size:18px;line-height:1.4}.cover{display:table-cell;vertical-align:middle;padding:0 20px}footer{position:fixed;width:100%;height:40px;left:0;bottom:0;color:rgb(255, 255, 255);font-size:14px}</style>
<div class="cover"> <img src="" data-mce-src=""><h1>EPA Scan Failed - Access Denied - DatacentreName</h1> Unfortunately you are unable to access Citrix resources at this time. It seems that your computer is not a corporate asset. The Citrix EPA scan must run successfully in order to access Citrix apps and desktops. Please note that only domain-joined corporate computers are eligible to access Citrix resources remotely. If you are using a corporate asset, please contact the Service Desk for assistance. </div><footer>IT Self-Service Portal<a href="" data-mce-href=""></a> | (tel) Canada 1 844 555 5555 | (tel) Outside Canada 1 555 555 5555</footer>

With this in place, we can now create the responder action and policy. From there we will bind to our APIPA LBVIP.

add responder action resp_epa-deny_act respondwithhtmlpage denied.html -responseStatusCode 200 -reasonPhrase true 
add responder policy resp_epa-deny_pol true resp_epa-deny_act 
bind lb vserver lbvs_epadeny_80 -policyName resp_epa-deny_pol -priority 100 -gotoPriorityExpression END -type REQUEST

Step 3: Creating the Session Policy & Action and Linking to Gateway

These commands will create a new session profile and policy and subsequently bind the policy to a Citrix Gateway (be sure to update your gateway object name). Adjust binding priority as necessary, but should be last in the order.

add vpn sessionAction DENYALL -transparentInterception ON -defaultAuthorizationAction DENY -homePage "" -clientlessVpnMode ON -clientlessModeUrlEncoding OPAQUE 
add vpn sessionPolicy DENYALL ns_true DENYALL bind vpn vserver YOURVSERVER -policy DENYALL -priority 200

And there we go. When a user fails an EPA scan (or skips it if you haven’t hidden the button to do so) they should receive that custom error page.


So although this article may be useful to a very small audience, hopefully, its concepts will be useful to some.

0 0 votes
Article Rating
Notify of
1 Comment
Inline Feedbacks
View all comments
1 year ago

Very useful for a customer of mine. Obscure yes, but useful. Thanks

Would love your thoughts, please comment.x