Skip to content
This repository has been archived by the owner on Jul 25, 2024. It is now read-only.

fix(website): use session cookie instead of ID token #188

Merged
merged 2 commits into from
Sep 23, 2021
Merged

Conversation

ace-n
Copy link
Contributor

@ace-n ace-n commented Sep 21, 2021

Session cookies are longer-lived, and are what we should've been using anyway.

@ace-n ace-n requested a review from engelke September 21, 2021 01:58
@ace-n ace-n requested a review from a team as a code owner September 21, 2021 01:58
@google-cla google-cla bot added the cla: yes This human has signed the Contributor License Agreement. label Sep 21, 2021
@ace-n
Copy link
Contributor Author

ace-n commented Sep 21, 2021

N.B: @engelke this does work with the API's GET /campaigns route, unlike the previous ID token approach. 😃

@ace-n ace-n requested a review from grayside September 21, 2021 19:46
@@ -46,12 +46,16 @@ def login_post():
# Only allow sign-ins with tokens generated in the past 5 minutes
return flask.abort(403, "Token deadline exceeded.")

# Configure response to store ID token as a session cookie
# Create session cookie
# See https://firebase.google.com/docs/auth/admin/manage-cookies#create_session_cookie
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

follow-up: should we redirect to login if the session cookie is expired, per the documented sample?

Copy link
Contributor Author

@ace-n ace-n Sep 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This route only executes upon POST /login.

(I don't think we currently require login for any views; we just hide links to them in the UI.)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two layers of auth here: authenticating with the website and delegating your identity to the website to make API calls.

For the first one, I assume we are doing something like https://firebase.google.com/docs/auth/admin/manage-cookies#verify_session_cookie_and_check_permissions and if that fails, I'm suggesting like the sample we direct users to log in.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That redirect makes sense on a non-/login page - but this code only executes on POST /login.

Basically, all that would happen is:

  1. User does GET /login
  2. Firebase JS does POST /login
  3. If auth fails, user is redirected to GET /login

(Worse still, that may create an 🚨 infinite loop! 🚨 )

response = make_response(redirect("/"))
response.set_cookie(
"session",
id_token,
session_cookie,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm glad we've found the right model to persist website authentication, but this doesn't seem like something the API should speak. Should the session cookies be used to create the expected Identity Token?

Every authentication mechanism the API supports represents testing, documentation, maintenance overhead.

Copy link
Contributor Author

@ace-n ace-n Sep 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This page seems to say that session cookies are preferred for initial auth.

I'm not sure about minting fresh ID tokens, but a quick internet search didn't reveal anything along these lines - so I'd guess that this isn't supported.

(Perhaps we could confirm all this with a Firebase person?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Session cookies to me mean HTTP session cookies, which means the browser forgets them when it is closed. I think that Firebase here is using that term to mean something else: long-lived ID tokens. Which is fine. These cookies will still eventually expire, so we might want to eventually have the website tell the user clearly that they have been logged out (after 5 days or whatever) and to try again.

This would explain why the API has to try to verify them as OAuth2 tokens or Firebase tokens. They have similar structures but are signed with different keys.

These tokens won't be accepted by Google APIs, which is perfect. That's what we want, a token that only provides identity which our own API will then use to decide authorization.

We need to test these over hours or longer, but I think you've found the solution.

Copy link
Contributor Author

@ace-n ace-n Sep 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@engelke agreed. (I didn't think clear-on-close was the default, but I stand corrected.)

RE testing: we can always mint session cookies with a short expiry period (e.g. 5 minutes) and test those.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These cookies have a 2 week expiration, which is a pretty standard "login period" for a website. That seems good to me.

I'm less sure we should directly use that cookie value to make API requests. It seems to me that a token that lasts for 2 weeks should be moved over the wire as little as possible. This might make a good, specific question to ask an expert.

@engelke
Copy link
Contributor

engelke commented Sep 22, 2021

I'm not sure what this is doing. Is the Firebase session cookie value being updated automatically and transparently by Firebase? Because it looks like the value in the request received by the website is the ID_TOKEN, just as before. Have we checked that this is updated when the token expires?

@engelke
Copy link
Contributor

engelke commented Sep 22, 2021

If this header is refreshed upon login, that's better than before, where the cookie value persisted. But it's still going to expired. Will Firebase just refresh it transparently, or will this force the user to log in again when it expires?

Copy link
Contributor

@engelke engelke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@grayside
Copy link
Collaborator

If this header is refreshed upon login, that's better than before, where the cookie value persisted. But it's still going to expired. Will Firebase just refresh it transparently, or will this force the user to log in again when it expires?

The intention is the cookie is valid for 2 weeks after login, then on two weeks when you go to the page, you need to re-login. A two week timer is pretty typical, this is what happens when google periodically asks you to log in. (Hence my point about login redirect as a next step, the browser sends the cookie, when the website realizes it's invalid we should send the user to a login page instead of throwing an error)

@ace-n
Copy link
Contributor Author

ace-n commented Sep 23, 2021

Revisiting this - after chatting with the Firebase folks, I think the right move here is actually to use ID tokens, and to auto-renew those periodically (e.g. call getIdToken() with every request) on the client.

@engelke I'm 👎 on merging this, unless it unblocks your progress towards Internal Preview. (If it does, we can merge + do a follow-up PR later.)

@engelke
Copy link
Contributor

engelke commented Sep 23, 2021

It is blocking me, but if we can merge #190 to main we can them update this branch to match main. And I can work from this branch without waiting for it to merge. It's just that I need to have the effect of both #190 and this one in a single place.

@engelke engelke merged commit 5858f25 into main Sep 23, 2021
@engelke engelke deleted the fix-auth branch September 23, 2021 20:34
@grayside grayside added the component: website Related to the application frontend. label Sep 28, 2021
@grayside grayside added this to the v0.5.0 milestone Sep 28, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
cla: yes This human has signed the Contributor License Agreement. component: website Related to the application frontend.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants