InvalidAuthenticityToken error despite the presence of SSL Certificate

Hello everyone,

Texas Tech here! I’m sure you have seen a few discourses opened by our staff members in the past requesting help. But as a matter of fact, despite our previous attempts at installing OOD in the test environment, we have never deployed the project for production to date. The good news is, we are very close to finalizing the deployment of OOD version 4.x and going fully online by the end of September.

However, we ran into a strange issue that is similar to the problems mentioned in various discourse:

In all cases above, the primary solution is to make sure a valid SSL certificate is installed and configured correctly.

The fact is, in our case, a valid SSL certificate is in place:

/etc/ood/config/ood_portal.yml:

...

servername: oodheadnode.hpcc.ttu.edu

server_aliases:

  - ondemand.hpcc.ttu.edu


ssl:

  - 'SSLCertificateFile "/etc/pki/tls/ssl/oodheadnode.hpcc.ttu.edu.pem"'

  - 'SSLCertificateKeyFile "/etc/pki/tls/private/oodheadnode_multi.hpcc.ttu.edu.key"'

  - 'SSLCertificateChainFile "/etc/pki/tls/ssl/oodheadnode.hpcc.ttu.edu.cer"'

...

And the configurations have been applied correctly in the HTTPD config files, and the portal loads with the HTTPS protocol and a valid SSL certificate:

/etc/httpd/conf.d/ood-portal.conf

...

<VirtualHost *:80>

  ServerName oodheadnode.hpcc.ttu.edu

  ServerAlias ondemand.hpcc.ttu.edu



  RewriteEngine On

  RewriteRule ^(.*) https://%{HTTP_HOST}:443$1 [R=301,NE,L]

</VirtualHost>



# The Open OnDemand portal VirtualHost

#

<VirtualHost *:443>

  ServerName oodheadnode.hpcc.ttu.edu

  ServerAlias ondemand.hpcc.ttu.edu

...

  SSLEngine On

  SSLCertificateFile "/etc/pki/tls/ssl/oodheadnode.hpcc.ttu.edu.pem"

  SSLCertificateKeyFile "/etc/pki/tls/private/oodheadnode_multi.hpcc.ttu.edu.key"

  SSLCertificateChainFile "/etc/pki/tls/ssl/oodheadnode.hpcc.ttu.edu.cer"

...

To clarify this further, the server’s hostname where the OOD service is running is (oodheadnode.hpcc.ttu.edu):

# hostname

oodheadnode.hpcc.ttu.edu

We also created a friendly alias (canonical) name to allow users to log in to the Portal via that URL (ondemand.hpcc.ttu.edu)

# nslookup ondemand.hpcc.ttu.edu

Server: 129.x.x.x

Address: 129.x.x.x#53



Non-authoritative answer:

ondemand.hpcc.ttu.edu canonical name = oodheadnode.hpcc.ttu.edu.

Name: oodheadnode.hpcc.ttu.edu

Address: 129.x.x.x.

And as you see in the configuration files above, we also generated the SSL certificates based on the server’s hostname, not the alias.

Below is the summary of what we have done:

  • The hostname is oodheadnode.hpcc.ttu.edu

  • SSL certificates are generated for oodheadnode.hpcc.ttu.edu

  • Portal’s alias is ondemand.hpcc.ttu.edu

  • The Shibboleth is set for ondemand.hpcc.ttu.edu(the alias)

  • Users can access the Portal via ondemand.hpcc.ttu.edu, where Shibboleth is set to.

However, when we log in to the ondemand.hpcc.ttu.edu, and select the “jobs → Job Composer” from the menu and click on “+New Job → From Default Template”, we encounter the following error:

The change you wanted was rejected.

Maybe you tried to change something you didn’t have access to.

If you are the application owner check the logs for more information.

That also leads to the following error we see in the log files:

/var/log/ondemand-nginx/<USER>/error.log

...
App 2316025 output: [2025-07-31 09:42:49 -0500 ] FATAL "[f203c030-5ab1-4711-bf6c-e56e11964548]
[f203c030-5ab1-4711-bf6c-e56e11964548] ActionController::InvalidAuthenticityToken (Can't verify CSRF token authenticity.):
[f203c030-5ab1-4711-bf6c-e56e11964548]
[f203c030-5ab1-4711-bf6c-e56e11964548] actionpack (7.0.8.5) lib/action_controller/metal/request_forgery_protection.rb:253:in `handle_unverified_request'
[f203c030-5ab1-4711-bf6c-e56e11964548] actionpack (7.0.8.5) lib/action_controller/metal/request_forgery_protection.rb:286:in `handle_unverified_request'
[f203c030-5ab1-4711-bf6c-e56e11964548] actionpack (7.0.8.5) lib/action_controller/metal/request_forgery_protection.rb:275:in `verify_authenticity_token'
[f203c030-5ab1-4711-bf6c-e56e11964548] activesupport (7.0.8.5) lib/active_support/callbacks.rb:400:in `block in make_lambda'
[f203c030-5ab1-4711-bf6c-e56e11964548] activesupport (7.0.8.5) lib/active_support/callbacks.rb:199:in `block (2 levels) in halting'
[f203c030-5ab1-4711-bf6c-e56e11964548] actionpack (7.0.8.5) lib/abstract_controller/callbacks.rb:34:in `block (2 levels) in <module:Callbacks>'
[f203c030-5ab1-4711-bf6c-e56e11964548] activesupport (7.0.8.5) lib/active_support/callbacks.rb:200:in `block in halting'
[f203c030-5ab1-4711-bf6c-e56e11964548] activesupport (7.0.8.5) lib/active_support/callbacks.rb:595:in `block in invoke_before'\n
...

We are not sure what we have done wrong with our configurations based on the server’s hostname, server alias, and SSL certificates. Or there may be a missing piece here that we have been overlooking as the documentations fall short in explaining the complexity we are faced with.

Please let us know if there is any other information we can provide. Thanks for your help!

Best Regards,
Misha

I think the issue here may have to do with how you are using ServerAlias and how Rails handles the POST for your request.

My thinking is because ServerAlias is not a redirect the host is not set correctly and so you end up getting rejected because the cookie host and requesting host don’t match. So, when a user opens https://ondemand.hpcc.ttu.edu but end up after authing in at https://oodheadnode.hpcc.ttu.edu which Rails then sets the session cookie for. But, then the POST from the job composer still goes to https://ondemand.hpcc.ttu.edu and you end up with the cookie’s host not matching the request host, and so you get the InvalidAuthenticityToken error.

An option to keep the ServerAlias may be to add a second code block for the Redirect directive to the apache virtualhost config to replace the alias so that users are put onto the correct host. This way, when a user hits ondemand.hpcc.ttu.edu they are put onto the canonical oodheadnode. The entire goal here is to force everyone onto a singe host, something like this:

# Redirect-only vhost for the alias code block to add
<VirtualHost *:443>
  ServerName  ondemand.hpcc.ttu.edu
  Redirect permanent / https://oodheadnode.hpcc.ttu.edu/
  SSLEngine on
  SSLCertificateFile      "/etc/pki/tls/ssl/oodheadnode.hpcc.ttu.edu.pem"
  SSLCertificateKeyFile   "/etc/pki/tls/private/oodheadnode_multi.hpcc.ttu.edu.key"
  SSLCertificateChainFile "/etc/pki/tls/ssl/oodheadnode.hpcc.ttu.edu.cer"
</VirtualHost>

# But keep the other block still
# Real OOD vhost
<VirtualHost *:443>
  ServerName oodheadnode.hpcc.ttu.edu
  # Now comment out the alias so the redirect above handles the request
  # ServerAlias ondemand.hpcc.ttu.edu   
  ...
</VirtualHost>

Another option is to try and remove the ServerAlias and have users just hit ondemand.hppc.ttu.edu to submit from. You’d have to issue and replace new certs for this obviously to match the hostname here and is likley not what you are after it sounds like, but I thought I’d mention it.

Let me know if these help or you need any more guidance. I’m certainly not an apache expert, so there may be other workarounds.

Hi Travis,

Thank you for your response. Actually, we did the second option as you suggested, removed the ServerAlias, and set the ServerName to “ondemand.hpcc.ttu.edu”, which is the alias for the oodheadnode. Then, generated a new set of SSL certificates for the “ondemand.hpcc.ttu.edu”. You can see the configurations below:

/etc/httpd/conf.d/ood-portal.conf
...
<VirtualHost *:80>
  ServerName ondemand.hpcc.ttu.edu

  RewriteEngine On
  RewriteRule ^(.*) https://%{HTTP_HOST}:443$1 [R=301,NE,L]
</VirtualHost>

# The Open OnDemand portal VirtualHost
#
<VirtualHost *:443>
  ServerName ondemand.hpcc.ttu.edu
...
  SSLEngine On
  SSLCertificateFile "/etc/pki/tls/ssl/ondemand.hpcc.ttu.edu.pem"
  SSLCertificateKeyFile "/etc/pki/tls/private/ondemand.hpcc.ttu.edu.key"
  SSLCertificateChainFile "/etc/pki/tls/ssl/ondemand.hpcc.ttu.edu.cer"
...

However, after restarting the httpd.service, we still get the same error:

/var/log/ondemand-nginx/USER/error.log
...
App 3040550 output: [2025-08-01 12:50:16 -0500 ] FATAL "[79134ae2-1cdc-484b-8874-a26e1dc5da58]
[79134ae2-1cdc-484b-8874-a26e1dc5da58] ActionController::
InvalidAuthenticityToken (Can't verify CSRF token authenticity.):
[79134ae2-1cdc-484b-8874-a26e1dc5da58]   
[79134ae2-1cdc-484b-8874-a26e1dc5da58] actionpack (7.0.8.5) lib/action_controller/metal/request_forgery_protection.rb:253:in `handle_unverified_request'
[79134ae2-1cdc-484b-8874-a26e1dc5da58] actionpack (7.0.8.5) lib/action_controller/metal/request_forgery_protection.rb:286:in `handle_unverified_request'
[79134ae2-1cdc-484b-8874-a26e1dc5da58] actionpack (7.0.8.5) lib/action_controller/metal/request_forgery_protection.rb:275:in `verify_authenticity_token'
[79134ae2-1cdc-484b-8874-a26e1dc5da58] activesupport (7.0.8.5) lib/active_support/callbacks.rb:400:in `block in make_lambda'
[79134ae2-1cdc-484b-8874-a26e1dc5da58] activesupport (7.0.8.5) lib/active_support/
callbacks.rb:199:in `block (2 levels) in halting'
[79134ae2-1cdc-484b-8874-a26e1dc5da58] actionpack (7.0.8.5) lib/abstract_controller/callbacks.rb:34:in `b
lock (2 levels) in <module:Callbacks>'
...

Any ideas? Are we missing something here?

Best Regards,
Misha

Thanks for the quick and detailed reply and sorry the work around isn’t working right.

This is surprising and I haven’t had luck finding a similar problem yet unfortunately. But, we also don’t see too much with Shib and that has me wondering about how it is fitting in here.

Could you do me a favor and open the dev tools in the job composer and under the Network tab, when you submit the job, can you post a screenshot of the POST request and the request headers associated with it? I am starting to think Shib/AD is doing something that I don’t quite understand with the host and seeing that may help clear this up.

Hi Travis,

Sure thing. Please see the attached screenshot and let me know if you can find what you need in there. If not, please let me know if there is anything else I can provide.

Best Regards,
Misha

I was hoping the quality of the screenshot would appear better here! :neutral_face: . I’m copying and pasting the Response and Request headers here:

Response Headers (Raw):

HTTP/1.1 422 Unprocessable Entity
Date: Fri, 01 Aug 2025 21:16:10 GMT
Server: nginx + Phusion Passenger(R)
Content-Security-Policy: frame-ancestors https://ondemand.hpcc.ttu.edu;
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Content-Type: text/html; charset=UTF-8
Content-Length: 1334
Status: 422 Unprocessable Entity
X-Runtime: 0.009398
X-Request-Id: 379811ad-ed0d-40f7-a6d9-2ea05b920485
X-Powered-By: Phusion Passenger(R)
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Request Headers (Raw):

POST /pun/sys/myjobs/create_default HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: en-US,en;q=0.9,fa;q=0.8
Cache-Control: max-age=0
Connection: keep-alive
Content-Length: 118
Content-Type: application/x-www-form-urlencoded
Cookie: _job_constructor_session=IkH4SpHxJWHWATnWbAeFc8Wuv8KvN4O%2BpxvtDWsiUssbQIi55Z2vj8lq6ML%2Bo2EAx67Rf%2BTSC3jolOMt19hkALqkLUGI5IvMib2NUIV2XI6PYNBNA09tu7znctx5JwnO0WA05w4y6FQG9GrNopJc%2Bv8%2BVuygOyiXVMz8U8PDjizHjVpmXX0XH9BO8rlrIIf0CjyPg8QJ4ZkCW%2Fv4Col6B23OtWnH1aKTmyFtMPjx%2BWPvyXaY0u0vI6kdoXhoiQtCEl4wQ7gUO4mNBrZJ0WKq4jy2GOaupdE5fjROLAN5wos%3D--pKaTkhEOyXbEsiL3--y4YJDLRAEJgkzqpwVBCIcA%3D%3D; _ga_RQYHTPXKFK=GS1.2.1725909892.2.1.1725910109.0.0.0; _ga_YV0K5KEK8Y=GS1.1.1725909892.1.1.1725910111.0.0.0; _ga=GA1.1.1691375591.1696282538; _ga_8Z1YQFNDLJ=GS1.1.1726069638.6.0.1726069638.0.0.0; _ga_0B3QMP3QX7=GS1.1.1726069638.3.0.1726069638.0.0.0; _gcl_au=1.1.355988319.1749484228; _hjSessionUser_6385707=eyJpZCI6ImZjZjdiZDA1LTllOWQtNTZhYy1hNzg4LTE5YmE2NWI1ZmQ2NCIsImNyZWF0ZWQiOjE3NDk0ODQyMjg0ODksImV4aXN0aW5nIjp0cnVlfQ==; _ga_KYDNSFJH6D=GS2.1.s1749663331$o10$g0$t1749663337$j54$l0$h0; _ga_B27HBMC8B7=GS2.1.s1749663331$o4$g0$t1749663337$j54$l0$h0; _ga_41CLQ33B17=GS2.1.s1749663331$o4$g0$t1749663337$j54$l0$h0; _ga_7ZEQ959VGG=GS2.1.s1749663331$o4$g0$t1749663337$j54$l0$h0; _opensaml_req_ss%3Amem%3Af5f10676d7a947b9b8e88888297d31989ee7d35b6fd22ffdf02a385057efc25e=_e0dd9e5da3bb9ec9f417a615b5f246b3; _opensaml_req_ss%3Amem%3Acac126881069a69183ddafea24d562d6453bb872cc6d986ddbe3851be4a55a5e=_a80b8f8234136ae745ccb73f911ebf3c; _opensaml_req_ss%3Amem%3A506063cdf9bbe1e7525efb48afbec9d7202d2cd5033660dc73cf92f7cb5d52d7=_e91fda7f6126b4baeda6bf79c593539a; _opensaml_req_ss%3Amem%3Ad6b008471c58bdc68474bfdfa1ec3d05364100ff4b923aeaaf7049e547c6f745=_52543bd3bb251266e7374ab39cd757a4; _opensaml_req_ss%3Amem%3Acabfc77a12c7b87180ebc34ba3c2a11d225edb551da7b8bd4ac57c9a0afb1dd3=_4ff42d48d11bf3fb3467733659b081a4; _opensaml_req_ss%3Amem%3A01480065be0198fe988c47d6da444affdb73b45504351ac4e18deb606cb29598=_baad47da86cffb68d437d988b1f1dbef; _opensaml_req_ss%3Amem%3A6586c3217bfe0b7b58f10fc715efeb61267d6cbe99f79419ce13db14b893a883=_749a58cb7136739dde34da436757c8de; _opensaml_req_ss%3Amem%3Aa3ebd23feb15f48e9c4c098289963a812414f6d58a0a9ec95aa2f5801064625b=_83e7c3434f8767c30746c34051d7db12; _shibsession_64656661756c7468747470733a2f2f6f6e64656d616e642e687063632e7474752e6564752f73686962626f6c657468=_ab9f5cb700cbeeb98878bddb55d06aeb
DNT: 1
Host: ondemand.hpcc.ttu.edu
Origin: https://ondemand.hpcc.ttu.edu
Referer: https://ondemand.hpcc.ttu.edu/pun/sys/myjobs
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36
sec

Best,
Misha

Good morning,

Just checking to see if you have any updates on this or if you need us to provide more information. We’ve aimed for the end of September to have the OOD fully up and accessible to all users, but unfortunately, we’re stuck with this issue despite having a valid SSL certificate in place and following the documentation carefully.

Thank you for helping with this case!

Best Regards,
Misha

Sorry for the delay in responding.

I was looking at this error specifically and investigating:

/var/log/ondemand-nginx/<USER>/error.log

...
App 2316025 output: [2025-07-31 09:42:49 -0500 ] FATAL "[f203c030-5ab1-4711-bf6c-e56e11964548]
[f203c030-5ab1-4711-bf6c-e56e11964548] ActionController::InvalidAuthenticityToken (Can't verify CSRF token authenticity.):
[f203c030-5ab1-4711-bf6c-e56e11964548]

Looking around I did find something similar here:

The setting they used to resolve their issue in the ood_portal.yml was:

custom_location_directives:
  - 'RequestHeader set X-Forwarded-Proto "https"'

And looking at the request header you shared above I’m not seeing that set at the moment. Try that with a restart of httpd and hopefully that moves you all along.

Hi Travis,

Thank you for the response. Unfortunately, that didn’t help either, and I’m still facing the same error. Besides, the CSRF error I’m getting here is slightly different compared to the other case:

App 826660 output: [2025-08-22 09:35:26 -0500 ]  WARN "[3d0a4687-24ab-4468-8f9b-fe9854b04db9] Can't verify CSRF token authenticity."
App 826660 output: [2025-08-22 09:35:26 -0500 ]  INFO "[3d0a4687-24ab-4468-8f9b-fe9854b04db9] method=POST path=/pun/sys/myjobs/create_default format=html controller=WorkflowsController action=create_default status=422 allocations=230 duration=0.79 view=0.00 db=0.00"
App 826660 output: [2025-08-22 09:35:26 -0500 ] FATAL "[3d0a4687-24ab-4468-8f9b-fe9854b04db9]
[3d0a4687-24ab-4468-8f9b-fe9854b04db9] ActionController::InvalidAuthenticityToken (Can't verify CSRF token authenticity.):

Looking online, this error seems to be very specific to Rails, and according to Googl,e it occurs when:

The ActionController::InvalidAuthenticityToken (Can't verify CSRF token authenticity.) error in a Rails application indicates that the Cross-Site Request Forgery (CSRF) protection mechanism has failed to validate the authenticity of a request. This typically occurs when the CSRF token submitted with the request does not match the token stored in the user’s session.

I’m totally blind to how OOD generates CSRF tokens and how the user’s session obtains theirs. I’m also sharing the content of the /etc/shibboleth/shibboleth2.xml Shibd uses in our settings as follows. I’m not sure how much that helps, but please feel free to let me know if you find something suspicious:

<SPConfig xmlns="urn:mace:shibboleth:3.0:native:sp:config"
    xmlns:conf="urn:mace:shibboleth:3.0:native:sp:config"
    clockSkew="180">

    <OutOfProcess tranLogFormat="%u|%s|%IDP|%i|%ac|%t|%attr|%n|%b|%E|%S|%SS|%L|%UA|%a" />

    <ApplicationDefaults entityID="https://ondemand.hpcc.ttu.edu/shibboleth"
        REMOTE_USER="eppn subject-id pairwise-id persistent-id"
        cipherSuites="DEFAULT:!EXP:!LOW:!aNULL:!eNULL:!DES:!IDEA:!SEED:!RC4:!3DES:!kRSA:!SSLv2:!SSLv3:!TLSv1:!TLSv1.1">

       <Sessions lifetime="28800" timeout="3600" relayState="ss:mem"
                  handlerURL="/Shibboleth.sso" checkAddress="false" handlerSSL="true" cookieProps="https"
                  redirectLimit="exact">

            <SSO entityID="https://idp.shibboleth.ttu.edu/idp/shibboleth">
              SAML2
            </SSO>

            <Logout>SAML2 Local</Logout>


            
            <LogoutInitiator type="Admin" Location="/Logout/Admin" acl="127.0.0.1 ::1" /

<!-- Status reporting service. -->
            <Handler type="Status" Location="/Status" acl="127.0.0.1 ::1"/>

            <!-- Session diagnostic service. -->
            <Handler type="Session" Location="/Session" showAttributeValues="false"/>

            <!-- JSON feed of discovery information. -->
            <Handler type="DiscoveryFeed" Location="/DiscoFeed"/>
        </Sessions>

        <Errors supportContact="root@localhost"
            helpLocation="/about.html"
            styleSheet="/shibboleth-sp/main.css"/>
        <MetadataProvider type="XML" validate="true" path="/etc/shibboleth/ttu-idp-metadata.xml"/>

        <!-- Map to extract attributes from SAML assertions. -->
        <AttributeExtractor type="XML" validate="true" reloadChanges="false" path="attribute-map.xml"/>

        <!-- Default filtering policy for recognized attributes, lets other data pass. -->
        <AttributeFilter type="XML" validate="true" path="attribute-policy.xml"/>

        <!-- Simple file-based resolvers for separate signing/encryption keys. -->
        <CredentialResolver type="File" use="signing"
            key="sp-signing-key.pem" certificate="sp-signing-cert.pem"/>
        <CredentialResolver type="File" use="encryption"
            key="sp-encrypt-key.pem" certificate="sp-encrypt-cert.pem"/>

    </ApplicationDefaults>

    <!-- Policies that determine how to process and authenticate runtime messages. -->
    <SecurityPolicyProvider type="XML" validate="true" path="security-policy.xml"/>

    <!-- Low-level configuration about protocols and bindings available for use. -->
    <ProtocolProvider type="XML" validate="true" reloadChanges="false" path="protocols.xml"/>

</SPConfig>

I also found out about the CSRF Headers in the /etc/ood/config/ood_portal.yml, which is commented out by default.

#CSRF Headers
#header_items:
#  - 'RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME}'
#  - 'RequestHeader set X-Forwarded-Host expr=%{HTTP_HOST}'
#  - 'RequestHeader set X-Forwarded-Port "443"'
#  - 'RequestHeader set X-Forwarded-For expr=%{REMOTE_ADDR}'
#  - 'ProxyPreserveHost On'

Is there anything in there we could possibly modify to help with the current CSRF issue?

Again, thank you for helping with this. We appreciate your support!

Best Regards,
Misha