-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Google authentication #24
Conversation
Error on Travis due to a conflict of elixir versions. |
add :refresh_token, :string | ||
add :key_id, :integer | ||
|
||
add :person_id, references(:people, on_delete: :nothing) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
|
||
def change do | ||
alter table("people") do | ||
remove :key_id |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SimonLab :key_id
is for storing the id of the encryption key used to encrypt the data in the same row as the data so that it's clear which key to use to decrypt it.
Are you planning to store the encryption key id somewhere else
? 💭
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes the key_id has been added to the sessions
table
see dwyl/app#247 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SimonLab yeah, I saw that 👍
However I expect the data in these two tables will be encrypted with different encryption keys. If someone registers to use the App using just an email address and password dwyl/app#237 (a use-case we will 100% be adding to support people who don't have/use Google Accounts) Then we will need to have key_id
in the people
table to know which encryption key was used to encrypt their data on sign-up. On each subsequent login the session data (e.g: IP Address and Browser User Agent) will be encrypted and stored in the sessions
table possibly with a different encryption key because of our key rotation system. 💭
Apologies that this is not clearly mapped out ... I don't expect you to guess what's in my head. 🙄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes makes sense, sorry I was focused on the google auth and hasn't thought of keeping the specific key_id for email/password authentication. I'll add it back 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Glad with the new solution for this. in-lining the key_id
is more "user-friendly" (to devs) 👍
@SimonLab do you have time to do a couple of pomodoros of pairing on this? |
I was a bit lost on how the associations works with Ecto so I'm working on this at the moment, ie creating people and sessions. I haven't looked at the failing build yet. I'll be on zoom |
@SimonLab OK. happy to pair on any part of the work if you are. |
lib/app/ctx.ex
Outdated
def create_session(attrs \\ %{}) do | ||
%Session{} | ||
|> Session.changeset(attrs) | ||
|> Ecto.build_ass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did you mean Ecto.build_assoc
? 💭
mix.exs
Outdated
@@ -44,7 +44,8 @@ defmodule App.MixProject do | |||
{:jason, "~> 1.0"}, | |||
{:plug_cowboy, "~> 2.0"}, | |||
{:elixir_auth_google, git: "https://github.com/dwyl/elixir-auth-google.git", branch: "master" }, | |||
{:fields, git: "https://github.com/dwyl/fields.git", branch: "update-ecto"} | |||
{:fields, path: "/home/simon/Documents/dwyl/fields"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this won't work very well on CI ... 😜
(but I get it that you're testing ...) 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
arf yes, well spotted, I'll add back the github link.
The Fields PR is now merged
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SimonLab thanks for merging the PR. 👍
I will add "enough" docs to fields
to publish it to Hex.pm 📦
so we no longer have to use the GitHub link. 🙄
@SimonLab it appears we are "suffering" from not having |
@SimonLab please ensure you have pushed your latest changes on this branch/PR so I can attempt to take a look at it over the weekend. (obvs you shouldn't be working on weekends, but I have to "catch up"...) |
I think this PR is ready for review now that the email/password authentication has been added. I've had a looked and removed unnecessary config and logs but otherwise it looks good to me. |
config/config.exs
Outdated
google_client_id: System.get_env("GOOGLE_CLIENT_ID"), | ||
google_client_secret: System.get_env("GOOGLE_CLIENT_SECRET"), | ||
google_scope: "profile email", | ||
google_redirect_uri: "http://localhost:4000/google/auth/callback" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
@@ -16,3 +16,6 @@ config :app, AppWeb.Endpoint, | |||
|
|||
# Print only warnings and errors during test | |||
config :logger, level: :warn | |||
|
|||
# mock elixir_auth_google | |||
config :app, :elixir_auth_google, App.ElixirAuthGoogle.Mock |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth documenting how this works somewhere?
def get_person!(id), do: Repo.get!(Person, id) | ||
def get_person!(id) do | ||
Repo.get!(Person, id) | ||
# |> Repo.preload(sessions: :person) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we don't need to preload
the sessions, this function can be restored to def get_person!(id), do: Repo.get!(Person, id)
Not urgent.
@@ -581,4 +614,23 @@ defmodule App.Ctx do | |||
def change_timer(%Timer{} = timer) do | |||
Timer.changeset(timer, %{}) | |||
end | |||
|
|||
alias App.Ctx.Session |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm increasingly not a fan of the "Contexts" in Phoenix.
They don't help to organise code, they simply dump all code in to Ctx
that should be in the same file as the schema or controller.
Not a problem with this PR more something that I'm going to fix in a future refactor. 💭
end | ||
|
||
def logout(conn) do | ||
configure_session(conn, drop: true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My reading of this function is that it will only drop the session for one browser tab.
If the user has multiple and only performs logout in one, will their session still be valid in the others?
OR will the cookie be destroyed for all tabs and thus invalidate the session?
(That still does not mitigate against a cookie replay though...) 💭
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is that the function will drop the session for the browser (ie all the tabs). I'll double check this on my localhost.
person = person_id && App.Ctx.get_person!(person_id) -> | ||
assign(conn, :current_person, person) | ||
|
||
true -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
true
catch all assigns :current_person
as nil
i.e. not authenticated. 👍
create_basic_session(conn, person) | ||
|
||
{:error, %Ecto.Changeset{} = changeset} -> | ||
url_oauth_google = ElixirAuthGoogle.generate_oauth_url(conn) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks very similar to the index
function above. could we just invoke that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we redirect to the index page we will loose the errors information contained in the changeset and the error won't be displayed to the user
<section class="tc"> | ||
<%= form_for @changeset, Routes.page_path(@conn, :register), fn f -> %> | ||
<div class="pa2"> | ||
<%= text_input f, :email, placeholder: "email" %> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be <input type="email" ... >
to allow browser to auto-complete email address.
https://hexdocs.pm/phoenix_html/Phoenix.HTML.Form.html#email_input/3
Co-Authored-By: Nelson <nelson+github@dwyl.io>
@@ -17,10 +17,6 @@ | |||
<%= text_input f, :email %> | |||
<%= error_tag f, :email %> | |||
|
|||
<%= label f, :email_hash %> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch. thanks for removing. 👍
on my
But when I attempt to login using Google I see the error: When I run the following command to reset the DB:
Apparently invoking @SimonLab want to pair on resolving this? |
Yes I had the same issue on localhost. When you reset your database you will also need to delete the cookie session manually. I think you must have manage to login and your session still exists but now the database doesn't contains the user. This case shouldn't happen in "real life" but we should still had a condition to check for it |
|
||
## Example | ||
|
||
iex> transform_profile_data_to_person(%{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need to update this example to use :atoms
as keys in the Map.
Not necessary for this PR. but good to do in next iteration. 💭
|> Map.put(:picture, profile.picture) | ||
end | ||
|
||
@doc false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SimonLab PR looks good, thanks! 👍
ref: dwyl/app#247
Use elixir_auth_google to allow users to signin using OAuth2 Google.