# How to check signature of ghost-members-ssr cookie in js

**URL:** <https://forum.ghost.org/t/how-to-check-signature-of-ghost-members-ssr-cookie-in-js/45495>\
**Category:** Memberships & subscriptions\
**Created:** [March 6, 2024, 1:21pm UTC](https://forum.ghost.org/t/how-to-check-signature-of-ghost-members-ssr-cookie-in-js/45495 "2024-03-06T13:21:41Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![roseash](https://avatars.discourse-cdn.com/v4/letter/r/258eb7/32.png) [@roseash](https://forum.ghost.org/u/roseash)\
**Post date:** [March 6, 2024, 1:21pm UTC](https://forum.ghost.org/t/how-to-check-signature-of-ghost-members-ssr-cookie-in-js/45495/1 "2024-03-06T13:21:41Z")

</div>

FWIU This [Use Ghost authentication to login to custom app](https://blog.benclmnt.com/blog/ghost-custom-app-auth) explains how the ghost-members-ssr cookie is hashed with the THEME\_SESSION\_SECRET to produce the ghost-members-ssr.sig cookie.

I am trying to work out how to check this signature using javascript - but totally bemused.

firstly it says the ghost-members-ssr cookie stores the user’s email - in actual fact it’s a guid not an email. But also my ghost-members-ssr.sig cookie value doesn;t look like an SHA hash to me (it is ‘nkZfmfcS8tw5L4hQm7fS6ntfn3Y’).

Have I got totally the wrong end of the stick here or have things changed…

here is the javascript I am using to check the signature:

```auto
import jssha from "jssha";

app.get('/process', asyncHandler(async (req, res) => {
  const shaObj = new jssha("SHA-1", "TEXT", {
    hmacKey: { value: process.env.THEME_SESSION_SECRET, format: "HEX" },
  });
  shaObj.update( req.cookies['ghost-members-ssr']);
  const hmac = shaObj.getHash("HEX");
  console.log({
    hmac,
    ssr: req.cookies['ghost-members-ssr'],
    sig: req.cookies['ghost-members-ssr.sig'],
    secret: process.env.THEME_SESSION_SECRET
  });
  if (hmac !== req.cookies['ghost-members-ssr.sig']) {
    throw new Error("auth fail");
  }
}));

```

it doesn’t work… I get:

```auto
{
  hmac: 'a4c38010dfbf3e0af3104b1701b52a190207583f',
  ssr: '----- redacted -----',
  sig: 'nkZfmfcS8tw5L4hQm7fS6ntfn3Y',
  secret: '--- redacted ----
}

```

---

<div class="post-metadata">

**Author:** ![Kevin](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/kevin/32/32_2.png) [@Kevin](https://forum.ghost.org/u/Kevin)\
**Post date:** [March 6, 2024, 1:41pm UTC](https://forum.ghost.org/t/how-to-check-signature-of-ghost-members-ssr-cookie-in-js/45495/2 "2024-03-06T13:41:14Z")

</div>

> `ghost-members-ssr.sig` which contains the base64-urlencoded SHA1-HMAC signature of the `ghost-members-ssr` cookie

It looks like you’re using the value of the cookie directly expecting it to be an SHA1-HMAC signature but it’s not, it’s that signature base64-urlencoded so you need to decode it first.

However, as you’re using JS you could use the same `cookies` package that Ghost uses, there are details in the article you referenced under the “Story time” heading.

---

<div class="post-metadata">

**Author:** ![roseash](https://avatars.discourse-cdn.com/v4/letter/r/258eb7/32.png) [@roseash](https://forum.ghost.org/u/roseash)\
**Post date:** [March 6, 2024, 2:14pm UTC](https://forum.ghost.org/t/how-to-check-signature-of-ghost-members-ssr-cookie-in-js/45495/3 "2024-03-06T14:14:28Z")

</div>

ok thanks - i will play with that. Also one thing I have realised is that the ssr cookie isn’t the email as the posts suggests - it’s the transient id from the members table…

---

<div class="post-metadata">

**Author:** ![roseash](https://avatars.discourse-cdn.com/v4/letter/r/258eb7/32.png) [@roseash](https://forum.ghost.org/u/roseash)\
**Post date:** [March 6, 2024, 2:47pm UTC](https://forum.ghost.org/t/how-to-check-signature-of-ghost-members-ssr-cookie-in-js/45495/4 "2024-03-06T14:47:35Z")

</div>

Thanks so much - a case of RTFM!

here’s working code:

```auto
import dotenv from 'dotenv';
dotenv.config();

import express from 'express';
import asyncHandler from 'express-async-handler';
import cookieParser from 'cookie-parser';
// import validUrl from 'valid-url';
import cookies from 'cookies';
import { method1 } from './src/lib.js';

const app = express();
 app.use(cookieParser());

app.get('/process', asyncHandler(async (req, res) => {
  const cks = cookies(req, res, { cookieSecure: true, keys: [process.env.THEME_SESSION_SECRET] });
  const value = cks.get('ghost-members-ssr', { signed: true });
  if (!value) {
    throw new Error("auth fail");
  }
  console.log({ value });
}));

// Define a custom error handling middleware
app.use((err, req, res, next) => {
    console.error(err); // Log the error for debugging purposes
  
    // Render a more descriptive error message as a JSON response
    res.status(503).json({ error: `An error occurred: ${err.message}` });
});

const port = process.env.PORT || 80;

app.listen(port, () => {
    console.log(`Server started on port ${port}`);
});

```

---

<div class="post-metadata">

**Author:** ![roseash](https://avatars.discourse-cdn.com/v4/letter/r/258eb7/32.png) [@roseash](https://forum.ghost.org/u/roseash)\
**Post date:** [March 7, 2024, 8:17am UTC](https://forum.ghost.org/t/how-to-check-signature-of-ghost-members-ssr-cookie-in-js/45495/5 "2024-03-07T08:17:56Z")

</div>

For reference - the ssr cookie has been changed to be a transient\_id not the email and the api does not appear to allow querying by transient id. It turns out all i needed to do was call /members/api/member/ from node using the cookies!
