Use SSO to feed an app based on JWT auth



In an app I try to integrate, it uses a cookie named token with a JWT token signed with HMAC SHA256. The JWT value is an email address.

I read the docs and the forum, but it is still unclear to me how an app integrates with the SSO, and if there are ways to configure the SSO at install time, so as the SSO creates the cookie — the user then arrives signed-in on the relevant service.

Do you have any pointers for me to look at thow it is doable?


Another way to formulate this is: at nginx level, if I write some lua code to interact with YunoHost SSO layer, which variables are available (username, email address, something else?)? And which utilities are available too, so as I can figure out a way to craft the expected cookie with the expected JWT value.

Thank you very much for your help, great project :slight_smile:

So I dug a bit in various existing scripts, and found out that getting the content of the SSOwAuthUser was a trick used in many places. Relying on the nginx.shared.cache was not reliable enough, as a restart would purge it (but the auth cookie would still exist).

For some reason, all Lua function that are able to generate HMAC SHA256 token do not generate a similar token as OpenSSL does. I’m too new to this to fully understand why—so I stuck to hmac_sha512 trick.

I added a rewrite_by_lua_file call in the location __PATH__/{ ... } block, with this content. Any improvement interests me, as I tried to do this by adding the least possible external code:

local cjson  = require 'cjson'
-- local hmac = require "openssl.hmac"
local str = require "nginx.string"

local user = ngx.var.cookie_SSOwAuthUser

if (user == nil or user == "") then

local user_email = user .. "@" ..

local function b64_encode(input)
  local result = ngx.encode_base64(input, true)
  return result:gsub("+", "-"):gsub("/", "_"):gsub("=", "")

local function hmac_sign (alg, message)
  local key = "__SECRET_KEY__"
  local pipe = io.popen("echo -n '" ..message:gsub("'", "'\\''").. "' | openssl " ..alg.. " -hmac '" ..key:gsub("'", "'\\''").. "' --binary | base64")
  local hash = pipe:read():gsub("+", "-"):gsub("/", "_"):gsub("=", "")
  return hash

local function gen_jwt_token (sub)
  local segments = {
    b64_encode(cjson.encode({ typ = "JWT", alg = "HS256" })),
    b64_encode(cjson.encode({ sub = sub, exp = os.time() + (24*60*60) }))

  local signing_input = table.concat(segments, ".", 1, 2)

  -- local signature = str.to_hex(, "sha256"):update(signing_input):final())
  -- segments[3] = b64_encode(signature)
  local signature = hmac_sign("sha256", signing_input)
  segments[3] = signature

  return table.concat(segments, ".", 1, 3)
end -- gen_jwt_token

local token = gen_jwt_token(user_email)
local cookie_content = "token=" .. token .. "; Path=__PATH_URL__/; Domain=__DOMAIN__; Secure; HttpOnly; SameSite=Lax"
ngx.req.set_header('Cookie', cookie_content)
ngx.header['X-Copanier-Token'] = token


This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.