Sunday, September 20, 2026

Why HTTPS Works in Browser but Fails in Mobile Apps: Understanding SSL Certificate Chains

Why HTTPS Works in a Browser but Fails in a Mobile App

A few days ago, I came across an interesting issue in a UAT environment.

The API URL was working perfectly fine when accessed through a browser, but the same API was failing from a mobile application.

At first glance, it looked like a mobile application issue.

But it wasn't.

The actual problem was with the SSL certificate chain configured on the server.

This is one of those issues that can waste quite a bit of time because everything looks fine when you test it from a browser.

The confusing part

Let's say our API is:

https://api.example.com

When we opened the URL in a browser, there was no obvious SSL warning. HTTPS looked perfectly fine.

But the mobile application couldn't establish the connection.

That raised the usual questions:

  • Is something wrong with the API?

  • Is the mobile app using the wrong URL?

  • Is there a network issue?

  • Is the SSL certificate expired?

  • Is the backend rejecting the request?

The certificate itself was valid.

The problem was that the server wasn't presenting the complete certificate chain.

What is a certificate chain?

An SSL/TLS certificate isn't always a standalone certificate.

There is usually a chain of trust involved:

Your Domain Certificate
        ↓
Intermediate CA
        ↓
Root CA
        ↓
Client Trust Store

For example:

*.example.com
      ↓
Intermediate CA
      ↓
Root CA
      ↓
Trusted by the client

The domain certificate identifies the server.

The intermediate certificate provides the link between the server certificate and the trusted root.

That link is important.

Why can the browser still work?

This is probably the part that causes the most confusion.

A browser may already have the required intermediate certificate available, or it may be able to retrieve it when necessary.

So you can end up with a situation like this:

Browser
   ↓
Server Certificate
   ↓
Finds intermediate certificate
   ↓
Connection works

Another client may not behave the same way:

Mobile App
   ↓
Server Certificate
   ↓
Cannot build complete trust chain
   ↓
TLS validation fails

So the fact that Chrome can open your website doesn't necessarily prove that every HTTPS client will be able to establish the connection.

That's what makes certificate-chain issues particularly confusing.

Certificate vs Full Chain

When you purchase or renew an SSL certificate, your certificate provider may give you several files.

For example:

example.crt
example.key
example.ca-bundle

The .crt is the server/domain certificate.

The .key is the private key.

The .ca-bundle contains the CA certificates required to build the trust chain.

The private key stays separate.

For Nginx, you generally create a full-chain file containing the server certificate followed by the required intermediate certificates.

For example:

cat example.crt example.ca-bundle > fullchain.pem

The important thing is the order:

Server Certificate
        ↓
Intermediate Certificate
        ↓
Additional Intermediate Certificate

You shouldn't simply assume that every certificate in a CA bundle needs to be sent by the server. Inspect the bundle and follow the CA provider's recommended chain.

Don't just trust the file — verify it

One of the useful tools for troubleshooting SSL problems is OpenSSL.

You can inspect the certificates in a CA bundle with:

openssl crl2pkcs7 -nocrl \
  -certfile example.ca-bundle | \
  openssl pkcs7 -print_certs -noout

This helps you understand:

  • Who issued the certificate

  • Which intermediate CA is being used

  • Which root CA is involved

  • How the certificate hierarchy is structured

You can also verify the certificate chain:

openssl verify -show_chain \
  -CAfile example.ca-bundle \
  example.crt

A successful result should look something like:

example.crt: OK

That's much better than simply assuming the certificate is correct because the browser doesn't show a warning.

Verify the certificate and private key

Another check I always recommend is making sure the certificate and private key actually belong together.

For RSA certificates, you can compare their modulus hashes:

openssl x509 -noout -modulus \
  -in example.crt | openssl sha256

And:

openssl rsa -noout -modulus \
  -in example.key | openssl sha256

The hashes should match.

Configure Nginx

Once the correct full chain has been prepared, Nginx should point to it.

For example:

server {
    listen 443 ssl;
    server_name api.example.com;

    ssl_certificate     /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/example.key;

    ...
}

The important part is:

ssl_certificate /etc/nginx/ssl/fullchain.pem;

rather than pointing only to the domain certificate.

After making the change:

sudo nginx -t

If everything looks good:

sudo systemctl reload nginx

But how do you know what the server is actually sending?

This is another important lesson.

Checking the certificate files on the server isn't enough.

You need to check what the server is actually presenting to clients.

OpenSSL can do this:

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

Look for:

Certificate chain

You should see the server certificate followed by the required intermediate certificates.

More importantly, look for:

Verification: OK

and:

Verify return code: 0 (ok)

This gives you much stronger evidence that the live HTTPS endpoint is presenting a usable certificate chain.

What about mobile applications?

It's important not to conclude that every SSL issue in a mobile application is a server issue.

Mobile applications can have their own TLS-related problems, including:

  • Certificate pinning

  • Custom trust stores

  • Network security configuration

  • Outdated device CA certificates

  • TLS version compatibility

  • Incorrect hostname validation

  • Proxy configuration

So if the server chain is correct and the mobile application still fails, the next step is to investigate the application's TLS configuration.

The key is to check both sides instead of immediately assuming one is responsible.

A simple troubleshooting checklist

When an HTTPS API works in a browser but fails from a mobile application, I usually check these in order:

✓ Certificate expiry
✓ Domain name / SAN
✓ Certificate and private key match
✓ Intermediate certificates
✓ Certificate chain
✓ What the server actually sends
✓ TLS configuration
✓ Mobile certificate pinning
✓ Mobile network security configuration

A few OpenSSL commands can answer most of the server-side questions very quickly.

The bigger lesson

SSL problems are often misunderstood because we tend to think about HTTPS as:

Certificate + Private Key = HTTPS

In reality, there is a trust relationship involved:

                Server
                  │
                  ▼
          Domain Certificate
                  │
                  ▼
           Intermediate CA
                  │
                  ▼
              Root CA
                  │
                  ▼
          Client Trust Store

If the server doesn't provide the certificates required to build that chain, different clients may behave differently.

That's why an HTTPS endpoint should be tested from the actual clients that consume it, not just from a browser.

A valid SSL certificate doesn't necessarily mean that your HTTPS server is correctly configured.

When an API works in a browser but fails in a mobile application, don't immediately start debugging the application code.

First, check the certificate chain.

Check what certificates the server is actually sending.

And verify the chain using OpenSSL.

A simple command like this can often reveal the problem:

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

The lesson is simple:

Don't just check whether the certificate is valid. Check whether the complete trust chain is being served correctly.

Sometimes a small SSL configuration issue on the server can look like a completely unrelated mobile application problem.