dwyl / auth Goto Github PK
View Code? Open in Web Editor NEW๐ช ๐ UX-focussed Turnkey Authentication Solution for Web Apps/APIs (Documented, Tested & Maintained)
Home Page: https://authdemo.fly.dev
License: GNU General Public License v2.0
๐ช ๐ UX-focussed Turnkey Authentication Solution for Web Apps/APIs (Documented, Tested & Maintained)
Home Page: https://authdemo.fly.dev
License: GNU General Public License v2.0
At present the /
(root route) of the Auth App displays the login buttons: http://localhost:4000/
This does not allow us to test redirection (back to the originating URL after successful login).
I suggest we create a different page in the Admin App to serve as a test for redirection.
/admin
routereferer
from request headersstate
when constructing url for 3rd Party AuthHigh value apps or those with sensitive personal data need extra security.
We need to make time to investigate Multi-factor Authentication (MFA)
https://en.wikipedia.org/wiki/Multi-factor_authentication
JavaScript
by @rajat-sr: https://hackernoon.com/how-to-implement-google-authenticator-two-factor-auth-in-javascript-091wy3vh3Note: we would prefer not use SMS-based solutions because:
mfa-research.md
file.If you have time + curiosity to help on this, please comment below!
Phoenix is now using Webpack for managing assets instead of Brunch.
We can try to upgrade this by changing the configuration in the asset folder:
https://github.com/dwyl/auth/blob/master/assets/brunch-config.js
As described in dwyl/app#267, email
is very important to the success of our App.
At present the Email section of the README.md
https://github.com/dwyl/auth#email indicates that auth
uses SES and Bamboo for sending email. It informs people that they need to have environment variables for SMTP_USERNAME
, SMTP_PASSWORD
, SES_SERVER
and SES_PORT
and links to dwyl/learn-phoenix-framework/sending-emails.md for more detail.
This is good for a barebones MVP that just needs to show a PO/PM that "email works",
but it is not a long-term solution to for reliably sending email because:
a) We are sending email
in a "fire and forget" manner expecting them to automagically reach their target recipient. But we all know there is a lot more to email
deliverability than simply sending the email
.
How do we know it was actually delivered to the recipient?
b) We don't have any end-to-end tests for email
so we have no way of knowing it's working other than to manually test sending an email to ourselves. Manual testing gets old fast.
c) Assuming the email
is successfully delivered we have no way of knowing if it was opened/read.
We have no metrics for how effective our email is so we cannot be data-driven.
d) What happens when the email
bounces or worse there is a complaint about our service? Our deliverability rating will plummet and along with it the fate of our App.
e) We are forced to maintain email
related code in the auth
App which is really not the "focus" of the auth
App. Email should be a single function invocation that delegates to a dedicated service.
All of these issues lead us to believe that there is a much better way of doing email
.
More detail on why
Instead of using Bamboo
and writing Elixir
code to send email
,
we build a separate service that has only one job email
. ๐
Given that we are already using Amazon Simple Email Service (SES) for sending our email
,
why not make the email
service a Lambda
Function that we can invoke from any App or Programming Language?
email
Lambda function/service is much easier to test and maintain.
email
templates in Handlebarsauth
can delegate email
and focus on the one thing it needs to do; authenticate people.delivery
, bounce
& complaint
email
will be recordedemail
system can more easily be used and improved upon by the community.The downside of having a separate project/function for email
is that it's another thing to think about (and hold in your head) from the developer's perspective.
I feel this is minor given that a developer is already invoking a Bamboo function,
the only difference will be we invoke a Lambda function with the same data.
In case you're wondering, we intend to re-use most of the work done in #36 and #35 (responsive email templates), so almost no work will be "wasted", we just think there is a more effective and long-term maintainable way of doing email.
dpl
๐ฆElixir
: dwyl/aws-ses-lambda#8delivery
& bounce
dwyl/aws-ses-lambda#1There is obviously a lot more we can do with email
and that's part of the reason we want to split it out into it's own independent service. But this is all we need for the auth
service for now.
This will allow us to get back to focussing on building our App. ๐ฑ
"Forgot password is a useless feature if people are not even getting started on using your product"
Suhail Doshi (mixpanel) - How to Measure Your Product https://youtu.be/MABmQhOlmJA?t=975
We should build this feature for ourselves if we feel we need it.
Or if someone using our product sends us a support email requesting it.
As the title suggests... this is WiP I will push it up tomorrow. ๐
http://blog.itproven.com/technology/nodejs/social-login-with-hapi/
Having trouble on my branch...
On Monday we drew out the basic auth schema (including Roles, Permissions and User_Roles) on the witeboard in the Office together:
This issue/epic is our attempt to capture as much detail as we can so we can implement it.
If you are interested in this challenge, please read: wikipedia.org/wiki/Role-based_access_control
More detail on the roles schema in #27 (comment)
I will be adding it to here shortly โณ
#ย Todo
Should we use https://github.com/hapijs/hapi-auth-basic
or can we simplify it...? dwyl/app#52
At present the Auth MVP is using the <img>
versions for the login with buttons.
https://app-mvp-elm.herokuapp.com/auth
It works but looks inconsistent.
We can easily solve this by using the SVG+CSS buttons we painstakingly created:
This should not take very long as the code is already working. see: dwyl/elixir-auth-github#33 (comment)
The two biggest advantages of using an HTML+CSS+SVG button is the reduction of bandwidth
(faster page load time without relying on an image server i.e. no additional HTTP requests)
and the fact that button can easily be translated to any language. ๐ก
As someone who has just registered using my email address I would like to receive a confirmation email informing me that I have successfully registered.
Note: this is not an especially compelling "user story", perhaps a better one is the "forgotten password" journey...?
The API Settings page should be clean and focussed:
This is obviously just a rough sketch, but hopefully you get the idea.
(It should have some sort of navigation bar/menu to help people situate themselves, not shown here)
#42 (comment)
The slowest part of the Auth App is waking up the Email App to send an email once auth is successful. I propose that we invoke the Email /ping
endpoint to wake the Email app immediately when the page is rendered. Ideally do this asynchronously.
My current understanding of how auth
will work is that it will be a separate application that a calling app forwards requests to.
If this is correct, how do we want to handle multiple applications using auth?
Would we deploy multiple versions of the auth app?
Would one auth application handle multiple calling apps?
If a person login to the application using Google first, no password is saved in the database. If then the same person try to register/login with email/password the application find the existing user by email and will try to compare the hash password, however the current one on the database is nil
which break the password check:
We can not update the password when the user login as it will allow anyone to set the password for this user.
My idea is to send an reset
email to the user when she can will be able to setup the new password via a specific link
I keep resetting the Database to test Auth and when the API Key I created is no longer there,
I see this error:
Ecto.NoResultsError at GET /profile/apikeys/7
expected at least one result but got none in query:
from a0 in Auth.Apikey,
where: a0.id == ^"7"
We need a better 404 error with some styling.
People expect that "Login" (Authentication / Authorisation) "just works โข".
Nobody wants to have to re-authenticate each time they use a Web App1.
Being forced to re-authenticate creates usage friction and in some cases abandonment.
When Login fails it can be "catastrophic" to any app, getting it right is worth the investment!
1The exception to this rule is Online Banking, which has conditioned people to
expect
a short session duration. This makes perfect sense because financial services are transactional by nature; people login to their Online Banking to perform a specific task like "check balance" or "transfer money" which only takes a few clicks. Very few people have a reason to keep their Online Banking open for longer than a few minutes.
Automatically timing-out a session after 10 minutes of inactivity is the appropriate UX.
As a "user" (person using a web application)
I want to be able to login once and have the App remember me for as long as I'm using the app.
So that I don't have to keep logging in each time I use the App.
We don't want to force people to constantly login to the App because it gets "old" very fast and will result in people being less effective with their time (wasting time logging into apps is a "time tax" nobody wants to keep paying!)
sessions
Schema inserted_at
- (standard ecto/phoenix schema type: :naive_datetime
) when a record is inserted. Automatically set by the database which ensures record integrity. This is the start of the session.
cid
(Primary Key. Ecto type :string
) - the hash of the data being inserted (the Ecto changeset
minus the inserted_at
timestamp) such that we know that a record is unique and verifiable.
session_id
- (Ecto type :string
) - the hash of the data being inserted (the Ecto changeset
minus the inserted_at
timestamp) such that we know that a record is unique and verifiable.
person_id
- (Foreign Key: Auth.People.person_id
, Ecto type :string
) A reference to the person record. Note: as illustrated in the people
schema example #32 the person_id
can refer to an anonomyous (unregistered) person. The same session will continue after they register, this allows for traceability through the analytics/user-journey.
User Agents Table
device_id
- the unique identifier of the device including browser user agent and IP Address. this is an irreversible hash which is checked on each request to reduce the chance of session spoofing.
ip_address
- (Ecto type :binary
, Use ) the device IP used for securing the session.
end
- (Ecto type: :naive_datetime
) the time when the session ended (usually via "logout" in the case of a registered/logged-in person).
session
exampleThe row2 number in the table below corresponds to the action taken.
prev
when the session starts.end_at
column.row | inserted_at |
cid (PK) |
session_id |
person_id |
ip_address 2 |
end_at |
device_id |
prev |
---|---|---|---|---|---|---|---|---|
1 | 1541609554 |
2oGsEgN | 2oGsEgN | 9c | 208.67.13.92 | null |
1BA6546A | null |
2 | 1541609554 |
e096d100 | 2oGsEgN | 9c | 172.34.85.14 | null |
1BA6546A | 2oGsEgN |
3 | 1541609876 |
ab4362a3 | 2oGsEgN | 9c | 172.34.85.14 | 1541609876 |
1BA6546A | e096d100 |
1Again the row number is included purely for illustrative purposes and would not be needed in the actual table as we already have a
cid
as Primary Key.
device_id
You may have noticed in the sessions
schema above that a session record includes a reference to device_id
this is an attempt2 to track which device is being used for a particular session so that we can provide a better service.3
We have implemented this Device data "anonymisation" and hashing before in:
https://github.com/dwyl/hits#implementation-detail and https://github.com/dwyl/hits-elixir
So we can easily get the user_agent
and ip_address
data from the conn
2 The reason we say an "attempt" to track which device is making the requests is because we are aware of the fact that both IP Address and Browser User Agent are "spoofable" see: https://en.wikipedia.org/wiki/Spoofing_attack and therefore should not be the only means of trust when a sensitive query is performed.
3 Device list will be stored independently of personal information and used for service quality and analytics exclusively, not to charge iOS/Mac users more, airline/travel industry!!
We need a sophisticated approach to session management that will ensure
both flawless UX and excellent security for all people using our App on any device.
These are the areas we need to cover:
Anonymous Sessions - for people who are curious about the App/Site
but have not yet registered their email address to persist their interactions. ... going to come back to this later!
Registration with Email address.
Verification - email address is verified by clicking a link sent by email.
Re/Set Password - once the person has verified their email address we ask them to define a password so they can login again. This is the same form to be used in the case where the person cannot remember their password and wants to re-set it. (all that changes is the copy)
Login - the person logs into the App/Site using an email address and password. If either of these two are not present in the people
table (or invalid in the case when a password is incorrect), then login will fail with the appropriate (friendly) message. If email and password are valid, show the page they were attempting to reach or their "dashboard".
Logout - destroy the session on their machine/device and set the end_time
in sessions
table. #158
Each one of these checklist items will need it's own issue/story with UX/UI flow & logic.
I will get these opened shortly. โณ
If you are ever in any doubt as to what/how we should implement sessions (or anything else) for Auth, Google is the "reference implementation" to consult.
if you are not already using any Google Apps (G Suite, Gmail, Calendar, Drive, Docs, Meet, etc),
consider trying it out just for professional curiosity.
At present we are inserting an initial person into people
in seeds.exs
based on the ADMIN_EMAIL
environment variable. This person is the (first) "admin" of the auth app.
They will have full control over the auth app. The issue is that we don't want to hard-code too much data into the seed.exs
and we don't want to have 5 environment variables for defining the Admin person.
So when the Admin logs into the App for the first time, they see this:
We need to update the person record for the Admin when they successfully login with their Google Account.
With that in mind we need an upsert_person/1
function.
This will be useful for anyone who updates their Google/GitHub profile e.g: their profile picture and wants that change to flow through to their @dwyl profile.
#ย Todo
upsert_person/1
function that accepts a person
record and either creates a new record if one does not already exist or updates the existing record with the new values.@nelsonic We recently spoke about the types of tables that will be needed to create the auth module.
Almost all of the tables had a primary key of a CID.
I understand using a CID in some of the tables (for example, a users table). There was a table, roles
which was suggested, that didn't seem to have any confidential information in it but still contained a cid rather than a regular auto incrementing id.
I was wondering when is it 'over complication' to use a CID?
Suggestions are most welcome!
While attempting to update the dependency on hapi-auth-basic in time we see that the plugin has been "upgraded" with _breaking changes_ ...
So we've decided to return to this project and build out hapi-login as a drop-in full solution (which we can then run as a micro-service for our project(s) ...)
I'm a fan of the simplicity of storing the session token (JWT) in a cookie to reduce the amount of code that needs to be written to maintain the session. What do you think?
As a person using the dwyl app for the first time,
I want to get started with the minimal possible "friction"
So that nothing gets in my way on my journey to be more time-effective.
At present the AUTH_API_KEY
PR #42 is using exbase58
for Base58 encoding/decoding.
We need to:
auth_plug
sends the client_id
to the auth_url
when no valid JWT is found: lib/auth_plug.ex#L167
We need to verify the client_id
(decode_decrypt/1
followed by lookup in apikeys
)
and if the client_id
is valid, use the client_secret
to sign the JWT on successful authentication.
client_id
from the HTTP referer
client_id
is valid before displaying the "login buttons" page
client_id
not valid, return a friendly Error: 401: AUTH_API_KEY not valid
client_id
in the state
prop that gets sent to GitHub/Googleclient_id
from the state
(returned by Auth Provider)decode_decrypt/1
)client_id
in apikeys
client_secret
to sign JWTWith the completion of this issue Auth dwyl/app#268 will be fully functional!
Let's get it done!
As noted in the discussion in #34 ("How do we want to handle multiple applications using auth?"),
our objective is to let anyone connect to the App/API server or run the App on their localhost
using a single environment variable: DWYL_API_KEY
DWYL_API_KEY
they can use for the App.DWYL_API_KEY
should be the encrypted person.id
so we can easily check if a Key is valid simply by confirming that it decrypts into an integer. ๐กiex(1)> key = Fields.AES.encrypt(1)
<<48, 48, 48, 49, 56, 39, 172, 166, 103, 23, 208, 232, 132, 247, 86, 129, 106,
103, 135, 215, 140, 220, 234, 8, 178, 124, 86, 165, 28, 83, 55, 230, 137, 178,
114, 127, 27>>
iex(2)> Fields.AES.decrypt(key)
"1"
auth_plug
should send the first portion of the DWYL_API_KEY
(corresponding to the client_id
) to the auth_url
when a request fails. > dwyl/auth_plug#14decrypt_decode
the client_id
and then lookup in apikeys
#55In order to verify people's email address (for "double opt-in") we need to send them an email with a link that they need to click in order to verify their email address.
We have done before for Healthlocker and TC please see:
https://github.com/dwyl/learn-phoenix-framework/blob/master/sending-emails.md
If there are any "gaps" in the setup/sending please update/clarify. (thanks!)
@Cleop please work with @RobStallion on sending the "verify email address" email for Auth.
If you have any questions, please comment. (Thanks!)
We discuss this morning having a role-based access control system (https://en.wikipedia.org/wiki/Role-based_access_control)
Do we want to have the RBAC implemented inside the auth package or should we create another repository/package for it?
What makes a _Great_ Registration Form?
- https://github.com/braitsch/node-login - https://github.com/jedireza/drywall - https://github.com/jedireza/aquaTask: take screenshots of all the most successful login/registration forms...
Preferably for the services _before_ they were popular because now (_after_) they are ubiquitous their network effect forces people to register regardless of how much personal information they require...
Our initial requirements for this module:
Create an auth table/schema that is linked to a users table in the calling app. This means that we have some schema fields that we will define (username/email
, password
) but allows the developer using the module to define the fields that want their users to have. We'll need to make sure this works both with and without Append Only data.
Signup functions - endpoints or controller functions that create both the user and auth table. This will need to use the relevant auth/user changeset functions for casting/verifying passwords etc.
Encryption (see https://github.com/dwyl/phoenix-ecto-encryption-example) - encrypting user data for GDPR compliance.
Auth plug - a plug (or multiple plugs) that will allow us to authorise users and check permissions (eg. Admin permissions, edit permissions)
@nelsonic Does this sound like we're thinking along the right lines? Anything you think we should also think about to begin with?
People are the heart of the both the dwyl ("main") app and Auth system.
A person
record securely stores all personal data.
person
- the person using the App (AKA the "user" but we prefer the word "person" to "user" don't you?)
id
: Int
1inserted_at
: Timestamp
updated_at
: Timestamp
username
: Binary
(encrypted; personal data is never stored in plaintext)
Keeping the option of usernames open for now: #22
username_hash
: Binary
(salted & hashed for fast lookup during registration/login)givenName
: Binary
(encrypted) - first name of a person https://schema.org/PersonfamilyName
: Binary
(encrypted) - last or surname of the personemail
: Binary
(encrypted) - so we can contact the person by email duh.email_hash
: Binary
(salted & hashed for quick lookup)password_hash
: Binary
(encrypted)key_id
: String
- the ID of the encryption key used to encrypt personal data (NOT the key itself!)status
: Int
(FK status.id
) - e.g: "0: unverified, 1: verified", etc.We've already created this schema as part of the MVP.
See: https://github.com/dwyl/app-mvp-phoenix#create-schemas
I don't think we need any additional fields right now.
So I'm thinking of just borrowing the migrations:
tags
table by reusing 20191113100513_create_tags.exs
migration from the MVP:status
table by reusing 20191113100912_create_status.exs
from MVP: https://github.com/dwyl/app-mvp-phoenix/blob/master/priv/repo/migrations/20191113100912_create_status.exspeople
table by reusing 20191113100920_create_people.exs
migration from the MVP:person_id
to Tags using 20191113114340_add_person_id_to_tag.exs
from MVP:person_id
to Status using 20191113141229_add_person_id_to_status.exs
form MVP:And schemas:
person
: https://github.com/dwyl/app-mvp-phoenix/blob/master/lib/app/ctx/person.exstatus
: https://github.com/dwyl/app-mvp-phoenix/blob/master/lib/app/ctx/status.extags
: https://github.com/dwyl/app-mvp-phoenix/blob/master/lib/app/ctx/tag.exWith a minor twist. I hate the Context
in Phoenix. It adds an unnecessary layer of complexity.
So I'm going to remove it and just put the functions directly in the schema file in /auth
.
I'm thinking of writing an AWS Lambda function that receives an email and saves the contents to AWS S3.
Then we can read the file from S3 and confirm that the contents is what we expect.
This would prove that email is "working".
@iteles thoughts?
Note: it does not prove "deliverability", but we expect AWS SES to handle that for us.
As a person registering with their email address and password,
I should be required to enter a password of at least 8 characters.
to enhance the security of my account.
Need to
checkpw
Note: we will enhance this further with #66 in a future sprint.
For now we just need to prevent people from having a blank password (or one with too few chars).
Currently we are assuming people want to Authenticate into the dwyl app using Email & Password.
We have not collected any data on this so we don't know what people want/expect.
"please verify your email address"
email as soon as they enter a valid email address. #63Authenticating with Google, Facebook or GitHub could be an option depending on the use-case.
Please share your thoughts on which 3rd Party services you would like to login with
and which ones you have used in other apps or websites.
while trying to create an email-only registration form #14
assign @changeset not available in eex template
Just read through @teesloane's Auth Boss https://github.com/teesloane/Auth-Boss ๐
it's superb and I think we should link to it in the recommended reading section. ๐
So far the only decent-looking email validation is using this regex:
https://gist.github.com/mgamini/4f3a8bc55bdcc96be2c6
@nelsonic
What we've got so far is a working implementation of auth in an example app, but how should we go about using it in other projects?
Is the intention to keep the code in the form it is now when requiring it into other apps? By this I mean the logic being performed in the controllers
so that all the parent application has to do is forward all requests to /auth
endpoints to this application, rather than the alternative which, would just be exposing the functions in this app and the parent module calling these functions to perform authorisation.
You mentioned in dwyl/technology-stack#67 (comment) that Auth should eventually be its own, separately hosted umbrella app, so to me this does seem like a step towards that.
I have managed to get this method of integrating the apps working, but just wanted to check I wasn't heading in the wrong direction.
The main issue I had in getting this approach to work was the configuration. Dependency config files are not included when they are required as a dependency, as it is expected that the calling module will provide the config.
This was a problem as the Ueberauth plug that is being used in the auth_controller
expects some configuration to be set before it is compiled, so an error was being thrown. My solution to overcome this was to use Application.put_env
to set the config before the plug is called. This way we can set the config we want to specify in Auth
, and also read from the parent app's config file (with Application.get_env
), allowing certain configurations to be set.
On Monday we drew out the basic auth schema on the witeboard in the Office together:
This issue/epic is our attempt to capture as much detail as we can so we can implement it.
The schema defined herein is not meant to be "set in stone", rather it's a starting point which will allow us to ship and then iterate as new requirements surface.
While the photo of the schema above uses the word "users", this was only for the purposes of "sketching" it out on the whiteboard and is not the table/schema name we are going to use.
For more detail on why we are choosing to name the schema people
, see: dwyl/app#33
people
๐คAt the most basic level, we need a table to store encrypted email addresses and hashed passwords to allow a person to register and login to the app/service where auth
is being used.
inserted_at
- (standard ecto/phoenix schema type: :naive_datetime
) when a record is inserted. Automatically set by the database which ensures record integrity.
cid
(Primary Key. Ecto type :string
) - the hash of the data being inserted (the Ecto changeset
minus the inserted_at
timestamp) such that we know that a record is unique and verifiable.
This will use our excid
implementation: https://github.com/dwyl/cid
person_id
(Ecto type :string
) - this is a unique id for the person which allows queries to be performed across the table. For example, the following query will return the latest version of person record: SELECT * FROM people WHERE person_id = 'e096' ORDER BY inserted_at DESC LIMIT 1;
prev
(Ecto type :string
) - the reference to the previous cid
for the record.
This is "metadata" included by alog
which the person using the app will never see but is useful in an "audit trail" if we ever need to determine if a "rogue" DBA has altered records. If you haven't had exposure to data fraud/forensics see: wikipedia.org/wiki/Forensic_data_analysis
email_encrypted
(Ecto type :binary
) - encrypted email address which can be decrypted if/when we need to send someone an email from our App. This will use Fields.EmailEncrypted
to transparently apply strong encryption to the data before storing it.
email_hash
(Ecto type :binary
. Uses Fields.EmailHash
. Unique Index) - a (per application) salted sha256
hash of the person's email address which allows for fast lookup when the person is attempting to authenticate. This will use Fields.EmailHash
to transparently hash the email address. For more detail on why this is needed and how it works,
see: https://github.com/dwyl/phoenix-ecto-encryption-example
verified
(Ecto type :naive_datetime
) - the timestamp when the email address was verified. If this field is null
(not yet set) it means that the email address has not been verified. This will appear on the person's Profile as email unverified
and limit their actions in the App.
For example: on CS it will mean their reviews of a drinks/venues will only be visible to admins/editors until the email address is verified. This is to avoid spam content.
password_hash
- (Ecto type :binary
, uses Fields.Password
) - the Argon2
hash of the person's password, safely stored to avoid any risk of reversal in the unlikely event of a "database breach".
first_name
- (Ecto type :binary
, uses Fields.Encrypted
) the person's name. How we address them in emails and in UI customisations.
Notes: since we are never overwriting data in our append-only log,
updated_at
is not needed.
Also, you may notice that other schemas in our App have acreated_at
field to capture when a record was created (the timestamp when a task/timer that was created while the person using the app was offline...) this is not relevant to Auth because all changes to the Auth tables must be performed while the person is online.
people
Table Example (Encrypted/Hashed)1In the following example, the person
record "progresses"2 through various stages, these correspond to the row
number:
When the person first registers they will not have had an previous contact with the App,
therefore there is noprev
(previouscid
) to be linked back to.
Notice how the
prev
(previous hash) in the verification step refers to thecid
in the initial registration stepe096d1004
this referential integrity means that we know the data is valid (and has not been tampered with!)
person_id
- the person wants to have a specific "alias" in the App, so they update their person_id
to their desired handle.row | inserted_at |
cid (PK) |
person_id |
prev |
email_encrypted |
email_hash |
verified |
password_hash |
first_name |
---|---|---|---|---|---|---|---|---|---|
1 | 1541609554 |
9cC4os9MH | 9c | null |
null |
null |
null |
null |
null |
2 | 1541609554 |
e096d1004 | 9c | 9cC4os9MH | 1BA6546A0C5e7 | bmt3d2KpD | null |
null |
null |
3 | 1541609876 |
ab4362a37 | 9c | e096d1004 | 1BA6546A0C5e7 | bmt3d2KpD | 1541609876 | null |
null |
4 | 1541610203 |
MqEzBmto9 | 9c | ab4362a37 | 1BA6546A0C5e7 | bmt3d2KpD | 1541609876 | wKIGu6djDt |
null |
5 | 1541611381 |
tjGbE5BUd | 9c | MqEzBmto9 | 1BA6546A0C5e7 | bmt3d2KpD | 1541609876 | wKIGu6djDt |
NzKibHfx |
6 | 1541612984 |
ktBcXWZtp | alex | tjGbE5BUd | 1BA6546A0C5e7 | bmt3d2KpD | 1541609876 | wKIGu6djDt |
NzKibHfx |
1 values for
cid
,person_id
,email_encrypted
,email_hash
,password_hash
andprev
have all been truncated for brevity in this table (to reduce scrolling). In the real app, we would store the full hash, encrypted blob or CID for these fields/columns. The only exception to this isperson_id
which is a temporary value that the person can change e.g from9c
toalex
.
2 If you feel the "progression" of the person record is a "wasteful" way of capturing the data, remember that we are not concerned with how much disk space a record (or the evolution of a record) takes up, data is cheap! The value of the insight we derive from analytics far outweighs the cost of storing the extra data. Ask Amazon, Facebook or Google if they worry about data storage costs when capturing incremental analytics data ... they don't! They capture everything!
If anyone else using the Auth module/app in their own project feels they need to "clear out" older records, they can easily run a batch process to free up the disk space.
3If the UX designer prefers to capture both the person's email address, first name and password in a single registration form, they can! The Auth.people table will accept any combination of data to be inserted at any time. This means that registration can be easily A/B tested! ๐
##ย Anonymous
As you noticed, the tables from the Whiteboard photo (above) are not all included in this issue.
This is because we don't want this issue to be enormous so instead we are splitting out the remaining tables into linked sub-issues. And, in the case of Analytics a sub-project: https://github.com/dwyl/atm
sessions
: #30roles
, permissions
& people_roles
: #31analytics
: dwyl/atm#23alog
stores and retrieves records.alog
and fields
to create the people
schema.@iteles do you have a list of services we would like to allow people to login with?
e.g:
at the time of writing, https://github.com/hapijs/bell supports:
We have finished building the separate email service #39 https://github.com/dwyl/email โ
Now we need to use that service to send welcome emails when people authenticate.
/api/send
to send welcome email following the instructions in:As a person who (uses an iPhone and) wants to protect their privacy,
I want to be able use Sign in with Apple to authenticate with the @dwyl app
So that I can use the app without giving up my email address
(but still get email notifications routed via Apple).
One of our key differentiators as an app/company is our focus on privacy.
We aren't sending Analytics data to Google/Facebook/etc.
and we aren't mining anyone's data to build a "consumer profile" to sell to advertisers.
We are treating people's personal data as private
and encrypting it wherever we can.
People who care about personal privacy1 tend to use Apple iPhone because Apple's business model is high quality hardware and relates services (iCloud, Apps, etc) not harvesting personal data.
(yes, there are plenty of posers who buy iPhones as a status symbol, but let's focus on privacy)
We expect people who are privacy-focussed to identify strongly with what we are building.
And giving them the option to login with their Apple Account will reduce friction to adoption.
The benefits of Apple Login accrue to end-users in terms of privacy.
People whom we want to help maintain their privacy.
WSJ made an informative video explaining how Apple preserves privacy in their login service:
https://youtu.be/pmfjt2PPuVA
1 On the subject of "Which is the most private phone?" available,
Some people say the BlackBerry Key2 has even better privacy controls than Apple.
see: https://smartphones.gadgethacks.com/how-to/5-best-phones-for-privacy-security-0176106
But BB has only 0.04% market share in 2019 ... Down from 33% percent in December 2011 ๐ ๐ฎ
So it's not really worth spending too much time discussing BB, except as a lesson in strategic failure. ๐
Also, BB Key2 is powered by Android which means by default
it still sends lots of data to Google!
This is fairly obvious, but worth spelling out in terms of a Acceptance Criteria:
Requests to the Auth Homepage that do not include an HTTP Referer should:
state=dwylauth.herokuapp.com
/profile
on successful authentication.Requests to display the Auth buttons that include an HTTP Referer should:
client_id
in the URL query params.client_id
should be decoded and decrypted using decode_decrypt/1
client_id
is an Integer
look it up in apikeys
table!decode_decrypt/1
does not result in a valid Int
.state=referer?client_id=client_id
client_secret
for the given client_id
Reject requests that fail with 401
status code and friendly error message:
1. Sorry, the URL you defined for API KEY does not match the HTTP Referer. Please visit: dwylauth.herokuapp.com/profile/apikeys and confirm you have set the URL field correctly.
2. The API_KEY is not valid. Please visit: dwylauth.herokuapp.com/profile/apikeys and confirm you have the correct key.
At present we don't have any seed data so the database is empty:
We are having to manually create the data before people register otherwise there is no status=verified
.
I propose that we create a ADMIN_EMAIL
environment variable that defines the "administrator" of the Auth App. The Admin will be the "owner" of various status records necessary for running the App.
And when the person (owner of the ADMIN_EMAIL
) logs into the app using their Google/GitHub account the remaining profile data will be updated.
see: https://www.phoenixframework.org/blog/seeding-data
status="verified"
which can be applied to people who signin with 3rd Party OAuthThe email heroku app goes to sleep after a 30 mins of inactivity.
So the tests that sends an email fails with the following timeout:
** (MatchError) no match of right hand side value: {:error, %HTTPoison.Error{id: nil, reason: :timeout}}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.