Use Ghost members auth to log-in to custom app via cookies

I am creating a small app that to compliment the content on Ghost for my members and I would like a way for the app to only qualify members who are logged in via the Ghost site. To clarify, I would like to solely rely on Ghost’s authentication system for my app.

I did some scouting, it looks like the following cookies are stored for members.
__cfduid, ghost-members-ssr, ghost-members-ssr.sig, ugid

Additionally, after exploring the database a bit I found the following in the settings table:
members_public_key, members_private_key, members_email_auth_secret

I am also aware of possible relevant tables such as session and members. Could someone explain to me how they all tie together?

Here is my assumption of how it might work:

ghost-members-ssr.sig is the public key that I would use the members_private_key to decrypt via RSA, revealing the session info that I can use to check if the user is qualified i.e. ghost-members-ssr matches user email from backend and cookie has not expired. That said, there are some obvious gaps in my knowledge and I am unsure what the other cookie variables and members_email_auth_secret represent so I thought it would be best to check first before starting. Also, the decryption method is using RSA?

1 Like

I’m also interested in learning about this.

Hey!

This is definitely doable but it’s gonna be a hack either way as these are not publicly documented or stable methods.

You can either get a JWT for a member and use that to authenticate into your application, but this won’t handle logout when the member logs out of Ghost. Or you can use the cookies like you say, but this will be a little more involved and require your app to be running on the same domain so that the cookies can be shared.

External auth with JWT

You can make a GET request to /members/ssr in your theme which will give you a JWT and then send that to your application to validate (with members_public_key in the settings) and initiate a session. An example of a call to this endpoint is here: https://github.com/TryGhost/Ghost/blob/master/core/server/public/members.js#L75-L81

External auth with cookies

For this to work your app will have to be on the same domain as your Ghost site so they can share cookies.

You can take a look at the members-ssr package here: https://github.com/TryGhost/Members/tree/master/packages/members-ssr and use the getMemberDataFromSession method. In order to use this you’ll have to pass in the required settings which you can get from the Ghost settings table. You’ll also have to pass in a getMembersApi function which returns a proxy to a members API object - the only method you’ll need is this one: https://github.com/TryGhost/Members/blob/master/packages/members-ssr/index.js#L167

To implement this method you’ll need to use either the admin API or read from the db.

Hope this gives you a good start :relaxed:

3 Likes

Thanks @fabien, this answers so many of the questions I’ve had over the past week. We wanted to use Ghost’s authentication in order to benefit from its members system. Basically, have Ghost handle memberships for our app (that is on the same domain).

This kind of membership integration would make Ghost attractive to SaaS start-ups. Membership/subscriber and billing/payments available for their own service, and included in their blogging platform. A double win.

Or have I misunderstood how Ghost members works?

Those were very helpful indeed! I wanted to say I’ve implemented it but alas I can only say I’m nearly there (left with step 7 below)

  1. Custom JavaScript in theme to get a JWT via /members/ssr
  2. Push JWT to my app, which validates it using members_public_key and returns the app cookie.
  3. Cookie stores the email of the member, and has the same httpOnly, secure and sameSite settings.
  4. App is located as a subdir via nginx proxy.
  5. When user accesses the app, nginx checks if ghost generated cookie `ghost-members-ssr’ which stores the members email is the same as the apps generated cookie.
  6. On sign out, a custom JavaScript sends the members email to the app to remove the app cookie.
  7. If ghost cookie expires, app won’t authenticate since it requires both ghost and app cookies.

With this setup, I’ve adopted a hybrid approach to ensure a smooth auth experience across ghost and the app while implicitly benefiting from security features set by Ghost.

Personally I hope that members account will gain the ability to add names or handles. After tinkering with this possibility, the potential to extend Ghost to create simple, integrated communities instead of relying on third party services (Disqus) or fully featured platforms (Discourse) is closer to reality than I thought!

1 Like