Sharing authentication session with another app

Hello Elixir Forum !

I have an existing web app that I’d like to integrate within a new phoenix project. To provide context for those who might be familiar with it, that other app is JupyterHub, a multi-user server for the popular Jupyter data-science platform. But what I’m going to describe shouldn’t be specific to that particular app. In a way what I’m trying to achieve is the inverse of this : PASETO vs JOSE (JWT - JSON Web Tokens) (protocols/standards for managing user sessions) - #9 by idi527 I want to manage user accounts and login in my phoenix app and have my users be logged in automatically to the third party app.
I figured out how to control the login/logout process within the third-party app. It’s quite flexible, it could be based on calling an external service or on parsing a cookie. Both apps will be served under the same domain so it’s possible to share cookies between the two. In fact I managed to hack something together using Guardian and JWT. I works like this:

While it seems to be working, I’m not really happy with this solutions for a few reasons:

  1. there are security concerns with using JWT for authentication which I don’t fully understand
  2. JWT wasn’t designed for authentication in the first place, as mentioned several times in this forum by @OvermindDL1 and others
  3. it bothers me to transfer information (the user id) that I don’t really need to give to the user agent, even if it’s a signed cookie that in theory cannot be tampered with (we all know that cryptography sometimes end up being broken)

Ideally, I’d like to share only a session id between both apps. The third party app would receive that session id via a cookie that can be shared between both apps since they’re both on the same domain. The third party app would issue a request in the background to a protected endpoint of the phoenix app. That endpoint would return user information to the third party app, which would use that information to log the user in. Here is a diagram of the workflow I’m thinking of:

What do you think of this plan so far ?

I’m currently trying to implement something based on Phauxth, which seems to be simpler and easier to understand that Guardian. Now I’m trying to figure out I can implement the endpoint that takes a session cookie and returns user information. It seems to be a triple of dot-separated, base64-encoded strings, but not quite, as decoding its parts with Base.decode64/1 gives me an :error. Decoding it with GNU coreutils’ base64 program gives me this:

tm
  _csrf_tokenmcopw6CzJhZ+ZoPsm6jW9Dw==mphauxth_session_idmF94xYayLj2Ff17Aiw4base64: invalid input

Once I’ll have figured out the exact format of this cookie, I suppose I can retrieve the phauxth session and extract user info. So if you have more info about how the session cookie works, that would probably help me. I tried reading Plug’s source code but got a bit lost.

Edit: I found that the ETS session storage allows to retrieve the session data easily given just the session ID. I understand the drawbacks of this storage and I’m thinking of implementing a custom session storage for my PostgreSQL database.

Why do not implement or use a SSO ?

With this property, a user logs in with a single ID and password to gain access to a connected system or systems without using different usernames or passwords, or in some configurations seamlessly sign on at each system.

You can use that USER ID to store session data ( to database for example) and multiple apps can read database session data.

Yes that’s what I’m trying to achieve! In my post above I tried to describe the approaches I’m trying and the obstacles I’m bumping into.

If you want to archive the solution described above I think you can read or implement the OAuth2 RFC. Also if the app internally you can stick with SSO ( based on ip / LDAP )

I found this an elixir implementation for this: https://github.com/scrogson/oauth2 maybe will help you.

1 Like

They are reuseable within their active time period unless you store invalidation data on the server, which if you are doing that then there is no point in JWT to begin with. :slight_smile:

It’s good for database-less purely time-based non-invalidateable authorization, not authentication. :slight_smile:

If the apps share a backend, just pass a signed ID.
If the apps don’t share a backend but share signing keys, then use a token.
Else this might be a good case for JWT (transferring data safely between servers that have no connections between each other), though they’ll need each others public keys to verify the signature.

Oh that’s just a lot easier then, just make sure they share the same signing key for the cookie and good to go (or put in unsigned data if tampering is not an issue).

Actually what it looks like to me that you are trying to create is an SSO/OAuth/Etc server authentication, why not just use those standards?

Oh hey, yes this!

Just follow the spec and use existing libraries for it. :slight_smile:

1 Like

Thank you both for your replies!

From what I understand, OAuth was also designed to handle authorization, not authentication. Some have bended it to handle authentication by providing an authorized “user info” resource and this has even given birth to OpenID Connect, a standard on top of OAuth that is explicitly designed for authentication and which makes use of … JWT!

This is all very confusing and is nothing specific to Elixir or Phoenix so i shall not bother this forum more with this question. My problem of accessing session data is solved by the ETS session storage backend, which I may replace with a custom SQL-based backend later on.

1 Like