Ghost icon indicating copy to clipboard operation
Ghost copied to clipboard

No helpful errors when attempting to login without email setup

Open jrockwar opened this issue 8 months ago • 19 comments

Issue Summary

After upgrading from ghost:5.117.0-alpine to ghost:5.118.0-alpine, admin login is broken: no cookies are set in the browser, and Ghost logs show 403 errors with "Unable to determine the authenticated user or integration. Check that cookies are being passed through if using session authentication." Rolling back to ghost:5.117.0-alpine or earlier resolves the issue.

Steps to Reproduce

  1. Deploy Ghost using Docker with the ghost:5.118.0-alpine or ghost:5.118.1-alpine image.
  2. Use a standard nginx reverse proxy (as per this tutorial).
  3. Try to log in to /ghost/#/signin from a new browser or incognito window.
  4. Observe that no cookies are set and login fails with a 403.
  5. Revert Docker with ghost:5.117.0-alpine
  6. Try to log in to /ghost/#/signin from a new browser or incognito window. Login works successfully.
  7. Redeploy with the ghost:5.118.x-alpine image and try to login again. Login fails as described in (4)

If using the same browser that did the initial set-up, then the cookie is already set and login can be completed successfully.

Ghost Version

5.118.0 / 5.118.1

Node.js Version

v18.20.8

How did you install Ghost?

docker-alpine in a Hetzner VPS (Arm64 CAX11); via docker compose as per https://community.hetzner.com/tutorials/ghost-cms-on-arm64-debian

Database type

MySQL 8

Browser & OS version

Tested on MacOS Sequoia: Zen (Firefox) / Chromium / Safari; Android 15: Iceraven (Firefox), Chrome

Relevant log / error output

[2025-04-26 21:06:34] ERROR "GET /ghost/api/admin/users/me/?include=roles" 403 6ms

Authorization failed

"Unable to determine the authenticated user or integration. Check that cookies are being passed through if using session authentication."

Error ID:
    55d2b170-22e2-11f0-90d2-31b40eaea8c0

----------------------------------------

NoPermissionError: Authorization failed
    at authorizeAdminApi (/var/lib/ghost/versions/5.118.1/core/server/services/auth/authorize.js:33:25)
    at Layer.handle [as handle_request] (/var/lib/ghost/versions/5.118.1/node_modules/express/lib/router/layer.js:95:5)
    at next (/var/lib/ghost/versions/5.118.1/node_modules/express/lib/router/route.js:149:13)
    at authenticate (/var/lib/ghost/versions/5.118.1/core/server/services/auth/session/middleware.js:55:13)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Code of Conduct

  • [x] I agree to be friendly and polite to people in this repository

jrockwar avatar Apr 26 '25 23:04 jrockwar

Hi @jrockwar, that's all the expected behaviour with our new Device Verification security feature.

https://ghost.org/changelog/2fa/ https://github.com/TryGhost/Ghost/releases/tag/v5.118.0

The 403 error returned from the signin request itself will tell you that a code is required or what's wrong if there was an issue sending the code

The 403 from the request to GET /ghost/api/admin/users/me/?include=roles" is not the request to signin, this is the request used by the admin panel to determine if you're already logged in before showing you the signin screen, you'll see that request and 403 prior to 5.118 as well.

What's curious is you're not getting an error message related to email sending failure or some other issue that clarifies what's going wrong. Are you able to share the log from the actual signin request, which is to the ghost/api/admin/sessions/ endpoint?

ErisDS avatar Apr 27 '25 07:04 ErisDS

Note from our bot: The needs:info label has been added to this issue. Updating your original issue with more details is great, but won't notify us, so please make sure you leave a comment so that we can see when you've updated us.

github-actions[bot] avatar Apr 27 '25 07:04 github-actions[bot]

Thanks for replying @ErisDS ! This makes sense as email wasn't (isn't) configured yet in my freshly setup blog, so ghost couldn't have sent emails for verification.

However what I don't understand then is:

  • Why, as you say, I didn't get any other message with ERROR severity on the logs (from the browser point of view, the failure on the login page was completely silent and the page just hung).
  • Why the browser/device pair used for the initial setup of the blog can login successfully as staff without email being set up.

I think I saw some INFO messages about email, but nothing that sounded too ominous. I'll try to get you more logs / info so you can see whether this is expected behavior or a genuine issue.

In any case, different problem but there are dozens of tutorials out there for setting up ghost that assume that email isn't required but very much an optional step; it'd be great to update documentation to say it's now a hard requirement. This might make it inviable for some applications like internal documentation for teams on self-hosted environments where it's not feasible/practical to have a mailserver.

jrockwar avatar Apr 27 '25 08:04 jrockwar

This is a less-truncated version of the ghost logs:

[2025-04-27 08:51:30] INFO "GET /ghost/" 200 30ms
[2025-04-27 08:51:30] ERROR "GET /ghost/api/admin/users/me/?include=roles" 403 6ms

Authorization failed

"Unable to determine the authenticated user or integration. Check that cookies are being passed through if using session authentication."

Error ID:
    d00f3050-2344-11f0-a9d7-5d84571a68b5

----------------------------------------

NoPermissionError: Authorization failed
    at authorizeAdminApi (/var/lib/ghost/versions/5.118.0/core/server/services/auth/authorize.js:33:25)
    at Layer.handle [as handle_request] (/var/lib/ghost/versions/5.118.0/node_modules/express/lib/router/layer.js:95:5)
    at next (/var/lib/ghost/versions/5.118.0/node_modules/express/lib/router/route.js:149:13)
    at authenticate (/var/lib/ghost/versions/5.118.0/core/server/services/auth/session/middleware.js:55:13)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

[2025-04-27 08:51:30] INFO "GET /ghost/api/admin/site/" 200 6ms
[2025-04-27 08:51:30] INFO "GET /ghost/api/admin/authentication/setup/" 200 10ms
[2025-04-27 08:51:33] WARN Missing mail.from config, falling back to a generated email address. Please update your config file and set a valid from address
[2025-04-27 08:51:33] WARN Missing mail.from config, falling back to a generated email address. Please update your config file and set a valid from address
[2025-04-27 08:52:55] INFO "POST /ghost/api/admin/session" 200 100006ms
[2025-04-27 08:53:13] INFO "POST /ghost/api/admin/session" 200 100006ms

So there is a warning in there about the email. Plus if I leave it long enough, there is a... timeout? after 100 seconds.

However, interestingly, when I go to Settings > Staff, the setting for 2FA is disabled (note I never disabled it manually - this is how it came by default when I setup the blog on 5.118.1):

Image

On the browser side, all I get after 100 seconds is:

Image

Nothing is telling me in an obvious way that:

  • The email sending is failing
  • That email configuration is mandatory
  • That 2FA for Staff accounts is mandatory (or even enabled)
  • That 2FA for Staff accounts is failing

jrockwar avatar Apr 27 '25 08:04 jrockwar

I have also tried enabling Require email 2FA codes to be used on all staff logins and the output I get is identical - no new info on the logs or error message about any of the above. I think at the very least this should be more verbose, shouldn't it?

jrockwar avatar Apr 27 '25 09:04 jrockwar

Hey @jrockwar

ErisDS left some helpful links to documentation over on the forum: https://forum.ghost.org/t/cant-login-to-admin-dashboard-on-more-than-one-device/57135/3 - worth a read, if you haven't seen it yet.

As I understand it, that toggle affects whether all staff logins (new or old device) require a code, vs whether just new devices do. (So it doesn't really turn the behavior off, just reduces it. But the link above includes how to turn the behavior entirely off, if you need to. [It'd probably be better to configure outbound email instead, but...]

cathysarisky avatar Apr 27 '25 23:04 cathysarisky

A little update here - all the behaviour of Ghost reported here is expected EXCEPT for the lack of clear error messaging.

I definitely want to make all of this more transparent so it's easier to debug and fix, as well as making it clearer that email is required.

There's quite a few bits to do around docs and error handling.

One thing I don't have on this issue that would be SUPER helpful is a really, really clear reproduction case.

E.g. either step-by-step bullets outlining exactly what you did OR a screencast of you going through the motions would be amazingly helpful. It would significantly speed up the time it'll take me to find and resolve the issues, as well as ensure that I get the exact right cases.

(To be clear, when I run ghost locally for development I get super clear error messages, so it's not like this is the most obvious case)

ErisDS avatar May 01 '25 12:05 ErisDS

Alternatively of course if anyone else can already reproduce it, fixes are welcome!

ErisDS avatar May 01 '25 12:05 ErisDS

Hi @ErisDS,

Unfortunately I can't reproduce it anymore because now I've set up email properly in my blog, but up until then it was super easy to reproduce. I've written steps to reproduce (on the description).

​Set up:

​- Create a ghost blog from the docker image I've linked in the description, with v5.118+

​- Login to domain.com/ghost (this will work, and initially prompt the blog set up).

​After set up:

​- After the blog has been set up try logging in again: This will still work

​- Open an incognito browser or a browser on any other computer, go to domain.com/ghost: you won't be able to log-in, and the log in will hang.

​To "fix" the issue:

​- Revert the docker compose image to 5.117, relaunch ghost via docker compose down/up.

​- Try to log in on an incognito browser or other computer (that hasn't logged in before): the issue is gone.

​- If you then go back to 5.118, login on a new browser hangs again.

​alternatively,

​- Keep docker on 5.118 but enable email

​- Then things work as intended, as the login page sends an authentication email.

The details of my compose .yaml are in the link provided in the description - I followed that tutorial verbatim.

On May 1 2025, at 1:32 PM, Hannah Wolfe @.***> wrote:

ErisDS left a comment (TryGhost/Ghost#23050) (https://github.com/TryGhost/Ghost/issues/23050#issuecomment-2844750970)

A little update here - all the behaviour of Ghost reported here is expected EXCEPT for the lack of clear error messaging.

I definitely want to make all of this more transparent so it's easier to debug and fix, as well as making it clearer that email is required.

There's quite a few bits to do around docs and error handling.

One thing I don't have on this issue that would be SUPER helpful is a really, really clear reproduction case.

E.g. either step-by-step bullets outlining exactly what you did OR a screencast of you going through the motions would be amazingly helpful. It would significantly speed up the time it'll take me to find and resolve the issues, as well as ensure that I get the exact right cases.

(To be clear, when I run ghost locally for development I get super clear error messages, so it's not like this is the most obvious case)

Reply to this email directly, view it on GitHub (https://github.com/TryGhost/Ghost/issues/23050#issuecomment-2844750970), or unsubscribe (https://github.com/notifications/unsubscribe-auth/AHS5OVLJW2KPJ7FYVCW6NTT24IH6TAVCNFSM6AAAAAB354LMROVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDQNBUG42TAOJXGA).

You are receiving this because you were mentioned.

jrockwar avatar May 01 '25 12:05 jrockwar

temporary fix or bypass to turn off Auth code

https://ghost.org/docs/config/#security

security__staffDeviceVerification for docker

pong106 avatar May 03 '25 08:05 pong106

Thanks for replying @ErisDS ! This makes sense as email wasn't (isn't) configured yet in my freshly setup blog, so ghost couldn't have sent emails for verification.

However what I don't understand then is:

  • Why, as you say, I didn't get any other message with ERROR severity on the logs (from the browser point of view, the failure on the login page was completely silent and the page just hung).
  • Why the browser/device pair used for the initial setup of the blog can login successfully as staff without email being set up.

I think I saw some INFO messages about email, but nothing that sounded too ominous. I'll try to get you more logs / info so you can see whether this is expected behavior or a genuine issue.

In any case, different problem but there are dozens of tutorials out there for setting up ghost that assume that email isn't required but very much an optional step; it'd be great to update documentation to say it's now a hard requirement. This might make it inviable for some applications like internal documentation for teams on self-hosted environments where it's not feasible/practical to have a mailserver.

I second this. There have been so many published guides on how to pull this off because it’s not feasible for many. After this update hit I can’t login to admin panel without figuring out how to again setup mailgun which honestly, many don’t want to use. Would have been nice to have a heads up and trial this option not making it required by default giving self-hosting community time to deal with setup before being locked out.

JERXCHRS avatar May 10 '25 13:05 JERXCHRS

Holy moly this took an hour of my life. Thank you to @pong106 for the workaround my goodness. No error messages, nothing in the logs even in debug mode. How does stuff like this get past QA?

I added

environment:
	- security__staffDeviceVerification=false

to my compose file and can now login again.

ironicbadger avatar May 13 '25 14:05 ironicbadger

Holy moly this took an hour of my life. Thank you to @pong106 for the workaround my goodness. No error messages, nothing in the logs even in debug mode. How does stuff like this get past QA?

I added

environment:
	- security__staffDeviceVerification=false

to my compose file and can now login again.

Thank goodness! That’s exactly what I needed. I was on the verge of rebuilding my blog from the beginning today.

procrastinando avatar May 14 '25 12:05 procrastinando

I am not even really clear on how to configure things with my user so I can remove this line either.

ironicbadger avatar May 14 '25 13:05 ironicbadger

temporary fix or bypass to turn off Auth code

https://ghost.org/docs/config/#security

security__staffDeviceVerification for docker

for kubernetes kubectl edit deployment ghost

env:
- name: url
  value: https://yourdomain.com
- name: security__staffDeviceVerification
  value: "false"

kubectl rollout restart deployment ghost

aa6my avatar May 21 '25 09:05 aa6my

Holy moly this took an hour of my life. Thank you to @pong106 for the workaround my goodness. No error messages, nothing in the logs even in debug mode. How does stuff like this get past QA?

I added

environment:
	- security__staffDeviceVerification=false

to my compose file and can now login again.

Yeah this was frustrating. Thanks for the fix. More frustrating that I encountered it intermittently after deploy 3 separate sites. There are zero error messages that indicate what's going on, which is bad DX @ErisDS

damusix avatar May 25 '25 15:05 damusix

Holy moly this took an hour of my life. Thank you to @pong106 for the workaround my goodness. No error messages, nothing in the logs even in debug mode. How does stuff like this get past QA? I added

environment:
	- security__staffDeviceVerification=false

to my compose file and can now login again.

Yeah this was frustrating. Thanks for the fix. More frustrating that I encountered it intermittently after deploy 3 separate sites. There are zero error messages that indicate what's going on, which is bad DX @ErisDS

This definitely worked for casaos. I am grateful

dogukansahil avatar May 26 '25 15:05 dogukansahil

temporary fix or bypass to turn off Auth code

https://ghost.org/docs/config/#security

security__staffDeviceVerification for docker

I spent 2 days of my life looking for an answer to this... thank you, that worked

ChairBorn avatar May 28 '25 20:05 ChairBorn

I was having trouble logging in to my personal ghost site, and it turned out to be because of this. I dug into it, and I think I figured out what's going on, and why @ErisDS isn't seeing it locally. The default dev config is using SMTP, and it fails right away if it can't connect, generating the correct error.

However, the Docker container (which I am running, along with the OP and presumably others with this problem) makes a config with { "mail": { "transport": "Direct" } } automatically, apparently because it does not configure mail at all. Port 25 outbound is blocked on my connection, which I believe is generally the case these days unless you've specifically arranged something with your host or ISP.

What then seems to happen is that the nodemailer direct package tries, for a very long time, to send the email before eventually giving up after several minutes, which to the end user looks it's just broken.

I tried playing around with the retryDelay option on the nodemailer direct transport, but it still took a few minutes to actually throw the error. It looks like it tries a few times, and each try takes some time, but the retry only controls how long it waits before starting another attempt to send. The default is 15 minutes.

I am not sure there is an incredible solution here. It seems difficult to reliably tell port 25 is blocked, you may get slow rolled like this.

The best solution I can come up with is to, in direct mode, throw an error if the auth email has not been sent after some time. I picked 15 seconds, perhaps there is a better number, or perhaps it should be configurable. I am not sure how popular a successful Direct configuration is. It probably shouldn't be the default if no other config is set. I suspect a lot of people with Direct mode set just don't actually send emails, and it's only becoming a real problem now because of the 2FA.

TLDR: it's because in direct mode (set automatically in Docker) it can take well over 15 minutes for the email to fail.

PaulBernhardt avatar Jun 01 '25 19:06 PaulBernhardt

Our bot has automatically marked this issue as stale because there has not been any activity here in some time.

The issue will be closed soon if there are no further updates, however we ask that you do not post comments to keep the issue open if you are not actively working on a PR.

We keep the issue list minimal so we can keep focus on the most pressing issues. Closed issues can always be reopened if a new contributor is found. Thank you for understanding 🙂

github-actions[bot] avatar Sep 23 '25 06:09 github-actions[bot]