Question

Fix OpenSSL Certificate Verify Failed in Ruby on Rails

rubyruby-on-railssslauthlogicfacebook-graph-api

Question

I am using Authlogic-Connect to provide third-party sign-ins. After running the required migrations, Twitter, Google, and Yahoo logins work, but Facebook login raises this exception:

SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed

The development log shows:

OpenSSL::SSL::SSLError (
  SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
):
  app/controllers/users_controller.rb:37:in `update'

What does this certificate verification error mean, and how can it be diagnosed and fixed safely in a Ruby on Rails application?

Short Answer

This error occurs when Ruby/OpenSSL connects to an HTTPS service but cannot prove that the server certificate is trustworthy. You will learn how TLS certificate verification works, why one provider can fail while others work, how to inspect the failing certificate chain, and how to correct the trusted CA configuration without disabling security.

Concept

When a Ruby application makes an HTTPS request, OpenSSL performs two jobs:

  1. It encrypts traffic between the application and the remote server.
  2. It verifies that the remote server is really the service it claims to be.

For verification, the server sends a certificate and usually one or more intermediate certificates. OpenSSL attempts to build a chain from that certificate to a trusted certificate authority (CA) in Ruby's configured CA bundle or CA directory.

certificate verify failed means that this trust check could not be completed. Encryption may be available, but Ruby refuses the connection because it cannot safely authenticate the server.

Common reasons include:

  • The operating system or Ruby installation has an old or missing CA bundle.
  • Ruby/OpenSSL is configured to look in the wrong CA file or directory.
  • The remote service sends an incomplete certificate chain.
  • A corporate proxy intercepts HTTPS and presents its own certificate, whose CA is not trusted by Ruby.
  • The machine date and time are incorrect, so an otherwise valid certificate appears expired or not yet valid.

The text state=SSLv3 is from OpenSSL's internal, older-style state label. It does not by itself prove that the application is using the obsolete SSLv3 protocol. The important part is certificate verify failed.

Mental Model

Think of HTTPS as entering a secured office building.

  • Encryption is the locked conversation inside the building.
  • The server certificate is the receptionist's ID card.
  • Trusted CA certificates are the list of organizations allowed to issue valid ID cards.

Ruby checks whether the receptionist's ID was issued through a trusted chain of organizations. If a link is missing, expired, or unknown, Ruby does not enter—even if the receptionist has an ID card and the door can be locked.

Disabling certificate verification is like accepting any ID without checking it. It may make the error disappear, but it also makes impersonation attacks possible.

Take Quiz

Syntax and Examples

Ruby commonly raises this exception when an HTTPS client verifies a peer certificate:

require "net/http"
require "uri"

uri = URI("https://example.com/")
response = Net::HTTP.get_response(uri)

puts response.code

By default, a correctly configured modern Ruby HTTPS client verifies the server certificate. If OpenSSL cannot find a trusted path from example.com's certificate to a trusted CA, the request raises OpenSSL::SSL::SSLError.

You can inspect which CA locations Ruby/OpenSSL knows about:

require "openssl"

puts OpenSSL::X509::DEFAULT_CERT_FILE
puts OpenSSL::X509::DEFAULT_CERT_DIR

To inspect a remote certificate chain from a terminal, use OpenSSL:

openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null

Look near the end of the output for Verify return code. A result of 0 (ok) means the OpenSSL command was able to verify the chain using its current trust store. Test the actual hostname and port used by the failing OAuth or API request, not a placeholder hostname.

Do not use this as a permanent fix:

# Unsafe: accepts an untrusted or impersonated server certificate.
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

The correct solution is to repair the trust chain or CA configuration.

Step by Step Execution

Consider this simplified HTTPS request:

require "net/http"
require "uri"

uri = URI("https://login.example.test/token")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER

response = http.get(uri.request_uri)
puts response.code

Execution proceeds as follows:

  1. URI(...) separates the hostname (login.example.test), port (443 by default), and request path (/token).
  2. Net::HTTP.new prepares a network client for that host and port.
  3. use_ssl = true tells the client to make a TLS-protected connection.
  4. VERIFY_PEER requires the server certificate to be validated against trusted CAs. This is the secure setting.
  5. http.get starts the TLS handshake before sending the HTTP request.
  6. The server sends its certificate chain.
  7. OpenSSL checks signatures, dates, hostname, certificate purpose, and whether the chain ends at a trusted CA.
  8. If a required CA or intermediate certificate is unavailable or invalid, OpenSSL raises OpenSSL::SSL::SSLError. The HTTP request is never sent.

This explains why the error can appear on a controller line: that line probably triggers an OAuth token exchange or profile request, but the underlying failure happens during the HTTPS connection.

Real World Use Cases

Certificate verification is used whenever an application calls an HTTPS service, including:

  • OAuth sign-in: Exchanging an authorization code for an access token or fetching a user profile from an identity provider.
  • Payment APIs: Verifying the identity of a payment gateway before sending payment details.
  • Webhook delivery: Sending signed event data to another service over authenticated HTTPS.
  • Background jobs: Downloading feeds, calling partner APIs, or uploading files to cloud storage.
  • Internal services: Connecting a Rails app to company APIs that use certificates issued by an internal CA.

If Twitter or Google works while another provider fails, the application can probably make HTTPS requests generally. The difference may be the failing provider's certificate chain, hostname, endpoint, or the particular CA needed to validate it.

Take Quiz

Real Codebase Usage

In a real Rails codebase, certificate errors are usually handled by fixing deployment configuration rather than changing controller code.

Typical practices include:

  • Keep OS CA certificates current. Install or update the system ca-certificates package according to the operating system's documented process.
  • Use a maintained Ruby and OpenSSL build. Older runtime installations may ship with outdated trust-store paths or old root certificates.
  • Configure the CA bundle explicitly when necessary. In containers or custom Ruby builds, set the runtime's CA file/path using the supported deployment configuration, rather than hard-coding a random certificate file in application logic.
  • Add a private CA only when required. If an organization uses HTTPS inspection or internal certificates, install the organization's root CA into the trusted store through approved infrastructure tooling.
  • Log safe diagnostic details. Record the target hostname, exception class, and deployment environment. Do not log access tokens, authorization codes, or secrets.
  • Use retries carefully. Retrying can help transient network failures, but it does not fix an untrusted certificate. Treat certificate failures as configuration or server-chain problems.

A useful separation is: application code requests https://service.example/...; platform configuration provides the CA trust store that lets OpenSSL verify that service.

Common Mistakes

Disabling verification

# Do not use as a production fix.
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

This bypasses identity verification and can expose OAuth credentials or user data to a man-in-the-middle attacker. Fix the CA bundle, chain, proxy certificate, clock, or remote server configuration instead.

Assuming errno=0 means nothing is wrong

errno=0 means there was no ordinary operating-system socket error reported. The TLS verification failed at a higher layer, so the connection is still unusable.

Treating SSLv3 in the message as the root cause

The state text is not enough to diagnose the active protocol version. Focus first on the explicit verification failure. Use current Ruby/OpenSSL tooling to inspect supported and negotiated TLS versions if protocol compatibility is actually suspected.

Updating only the application gem

Updating an OAuth library may be useful for endpoint or protocol changes, but it does not automatically update the operating system's trusted CA certificates. Check both application dependencies and the server's CA store.

Testing only in a browser

A browser can have a different trust store and may fetch missing intermediates automatically. Test from the same server, container, and Ruby runtime that runs the Rails application.

Installing a certificate without validating its source

Do not download and trust a certificate from an unverified webpage. Obtain private CA certificates through the service owner or your organization's approved security process.

Comparisons

SituationWhat it meansAppropriate response
VERIFY_PEER succeedsThe server chain reaches a trusted CA and passes checks.Keep verification enabled.
VERIFY_PEER failsRuby cannot establish trust in the server certificate.Inspect the chain, CA store, proxy, and system clock.
VERIFY_NONE succeedsThe connection can be encrypted, but the server identity was not checked.Do not treat this as a fix; it is insecure.
Browser works, Ruby failsBrowser and Ruby may use different CA stores or chain-building behavior.Test with the deployed Ruby/OpenSSL environment.
One OAuth provider failsThe failing endpoint may use a different chain or CA, or be affected by a proxy rule.Inspect the exact failing hostname and endpoint.
Related errorTypical meaning
certificate verify failedThe trust chain, dates, hostname, or trusted CA validation failed.
hostname does not match the server certificateThe certificate does not identify the requested hostname.
certificate has expiredThe server certificate, intermediate, or local clock is outside its valid date range.
unable to get local issuer certificateThe local trust store lacks a needed trusted CA or intermediate path.
Take Quiz

Cheat Sheet

  • OpenSSL::SSL::SSLError is Ruby's TLS/SSL error class.
  • certificate verify failed means Ruby could not trust the remote server certificate.
  • Keep peer verification enabled:
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
  • Check Ruby's default CA locations:
require "openssl"
puts OpenSSL::X509::DEFAULT_CERT_FILE
puts OpenSSL::X509::DEFAULT_CERT_DIR
  • Inspect the exact remote endpoint from the affected host:
openssl s_client -connect host.example:443 -servername host.example -showcerts </dev/null
  • Check these first:

    • System date and time
    • OS/Ruby CA bundle availability and freshness
    • Complete server certificate chain
    • Corporate HTTPS-inspection proxy
    • Correct hostname and endpoint
  • Never permanently fix the issue with OpenSSL::SSL::VERIFY_NONE.

FAQ

Why does only one login provider fail with a certificate error?

Each provider can use different hostnames, certificate chains, and CAs. A missing or outdated trust entry may affect one endpoint while other HTTPS requests still work.

Is state=SSLv3 proof that my application uses SSLv3?

No. It is commonly an OpenSSL state-string detail in older error output. The explicit problem is certificate verification. Check negotiated protocol details separately if needed.

Can I set VERIFY_NONE temporarily to make OAuth work?

It may bypass the error, but it disables server identity checks and is unsafe. Use it neither as a production fix nor as a substitute for diagnosis.

How do I know whether the problem is on my server or the remote service?

Run openssl s_client from the same machine or container using the exact hostname. Also compare results with a current environment. A failing public chain may indicate a remote configuration issue; a failure only in your environment often indicates a local CA or proxy issue.

Could an incorrect system clock cause this error?

Yes. Certificates have validity dates. A clock that is far in the past or future can make valid certificates appear invalid.

Does updating Rails fix certificate verification failures?

Not necessarily. Rails may be unrelated. The relevant components are the HTTP client, Ruby/OpenSSL build, operating system CA store, network proxy, and the remote server's certificate chain.

What should I provide when reporting the issue to an API provider?

Provide the hostname, timestamp, OpenSSL verification result, and whether the issue reproduces from another current environment. Do not include OAuth tokens, client secrets, or authorization codes.

Take Quiz

Mini Project

Description

Build a small Ruby command-line HTTPS certificate checker. It connects to a hostname using peer verification and reports whether the server certificate is trusted. This mirrors the TLS stage that occurs before an OAuth client can call a provider API.

Goal

Verify an HTTPS endpoint securely and print useful certificate details or a clear verification error.

Requirements

Use Ruby's Net::HTTP and OpenSSL libraries.

Require a hostname argument, such as ruby check_https.rb example.com.

Connect using HTTPS with OpenSSL::SSL::VERIFY_PEER.

Print the HTTP status and certificate subject when verification succeeds.

Catch OpenSSL::SSL::SSLError and print a safe diagnostic message.

Take Quiz

Keep learning

Related questions

View more