Elixir with Auth0 #87 - JSToElm
All Episodes

Elixir with Auth0 #87

Why start with auth? Mostly because anything we'd want to connect or do with our site will require some level of user input, credentials to accomplish. Could we start with something else, like a feature? Sure, but sooner or later we'll need user auth / profile. So head down let's get to it.

Auth

I have no desire to roll my own. While a lot can be learned from this type of exercise, it is not something I want to get hung up on. Plus it’s a MONSTER subject. Not one to be taken lightly, so we’ll outsource the safe keeping of user info and the authentication mechanics. So we can focus on the implementation of it.

auth0 authenticated app

Adding some event counter for sampling

mix phx.gen.html Events Event events title due:datetime I’ve never been a fan of generators like this before, but I am also tired of hand carving the same things over and over in my React apps. So I’m all in.

Add the resource to your browser scope in lib/postit_web/router.ex:

    resources "/events", EventController


Remember to update your repository by running migrations:

    $ mix ecto.migrate
  • plus the cli is super nice and very informative
  • Add a route events to the router under lib/postit_web/router.ex within the scope of PostitWeb
  • Run migration. This I like. I know enough sql to find my way in the dark, but I much prefer to model in the API language I’m using, rather than back and forth. For JS I’m found of knex for that sort of thing. I do like the migration and rollbacks are generated with the phx.gen command. it always struck me as laborious and error prone to try and build those by hand. Also kinds gross.
  • In the Events Context we’ll add a list_future_events query
defmodule Postit.Events do
  @moduledoc """
  The Events context.
  """
  ...
    @doc """
  Returns the list of future events based on UTC

  ## Examples

      iex> list_future_events()
      [%Event{}, ...]


  """
  def list_future_events do
    query = from e in Postit.Events.Event,
      where: e.due >= ^DateTime.utc_now
    Repo.all(query)
  end
  • Then add these queried events to the homepage controller.

    • getting used to where things go
  • Binding query information for the template and what’s alais keyword for?
  • Edit in the page/index.html.eex to add the template to apply the data from the controller to the markup in the template. Curious about action binding. Not a huge fan of 2 way binding. So we’ll see.
  • Drop in the ‘Flipclock’ and jQuery to make it work,
  • CSS and JS are in assets. it’s a bit of a funny feeling to see them, not in the make lib of an application I’m working on. Bit odd really.
  1. Sign up for auth0

    1. Create New App as ‘Regular Web App’
    2. Allowed Callback URLs under settings will need our urls to redirect back to our app, once the user has been authenticated. http://0.0.0.0:4000/auth/auth0/callback for local dev. We’ll also want to add https://postit.blog/auth/auth0/callback for our deployed system.
    3. Add social systems. For now we’ll leave that. We’ll want to add github, twitter, and we’ll need to wrap our own for Micro.Blog sooner rather than later.
    4. Authenticated versus Authorized
    5. Who are you versus What are you able to do?
  2. Add Ueberauth as a dependency and an extra_application <- What does that even mean to have extra applications?

    1. Add Ueberauth configurations to /config/confix.exs
    2. Feel pretty good to remember where things are after taking a short break.
  3. Create a user model

    1. read/map user info from multiple sources
    2. I like that we are manual building the user model, rather than using the generate cli, doing this a couple times manually I feel like I’ll better know what it’s doing when I generate these down the road. Also, Where is everything?
    3. I don’t know what alias is ?
    4. Currently no model folder in “postit_web” so we’ll make the folder and the file?
Compiling 18 files (.ex)
warning: variable "auth" does not exist and is being expanded to "auth()", please use parentheses to remove the ambiguity or change the variable name
  lib/postit/user_from_auth.ex:27

warning: variable "auth" does not exist and is being expanded to "auth()", please use parentheses to remove the ambiguity or change the variable name                                           lib/postit/user_from_auth.ex:28

warning: function avatar_from_auth/0 is unused
  lib/postit/user_from_auth.ex:26


== Compilation error in file lib/postit/user_from_auth.ex ==
** (CompileError) lib/postit/user_from_auth.ex:27: undefined function auth/0
    (elixir) src/elixir_locals.erl:107: :elixir_locals."-ensure_no_undefined_local/3-lc$^0/1-0-"/2
    (elixir) src/elixir_locals.erl:107: anonymous fn/3 in :elixir_locals.ensure_no_undefined_local/3
    (stdlib) erl_eval.erl:680: :erl_eval.do_apply/6
    (elixir) lib/kernel/parallel_compiler.ex:208: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6
  1. Nothing beats debuging after typeing it out.

  2. Create an auth controller

    1. handles callback
    2. successful callback with then call the find_or_create that we made earlier and handle any failures on it’s part
    3. logout
    4. removed session
    5. redirect to home page
    6. helpers
    7. not totally sure what Ueberauth.Strategy.Helpers or Router.Helpers are for that matter
  3. Add endpoints for the controller to the Router

    1. need to understand the order of the router
    2. HTTP Type, domain path, Controller, and then controller function?
  4. Secure endpoints with Plug

    1. this will check our current session for a verified user
    2. writing our own plug,
    3. what’s halt?
    4. the idea of the plug is to be called by the controller prior to every endpoint.
  5. Adding current_user property allowing us to access it elsewhere ?

[error] #PID<0.554.0> running PostitWeb.Endpoint (connection #PID<0.553.0>, stream id 1) terminated
Server: localhost:4000 (http)
Request: GET /auth/auth0/callback?code=v06g_ILWwJvcOOOK
** (exit) an exception was raised:
    ** (ArgumentError) argument error
        (postit) lib/postit/user_from_auth.ex:27: UserFromAuth.avatar_from_auth/1
        (postit) lib/postit/user_from_auth.ex:34: UserFromAuth.basic_info/1
        (postit) lib/postit/user_from_auth.ex:19: UserFromAuth.find_or_create/1
        (postit) lib/postit_web/controllers/auth_controller.ex:23: PostitWeb.AuthController.callback/2
        (postit) lib/postit_web/controllers/auth_controller.ex:1: PostitWeb.AuthController.action/2
        (postit) lib/postit_web/controllers/auth_controller.ex:1: PostitWeb.AuthController.phoenix_controller_pipeline/2
        (phoenix) lib/phoenix/router.ex:280: Phoenix.Router.__call__/2
        (postit) lib/postit_web/endpoint.ex:1: PostitWeb.Endpoint.plug_builder_call/2
        (postit) lib/plug/debugger.ex:122: PostitWeb.Endpoint."call (overridable 3)"/2
        (postit) lib/postit_web/endpoint.ex:1: PostitWeb.Endpoint.call/2
        (phoenix) lib/phoenix/endpoint/cowboy2_handler.ex:33: Phoenix.Endpoint.Cowboy2Handler.init/2
        (cowboy) /c/Users/jtomc/Documents/Elixir/postit/deps/cowboy/src/cowboy_handler.erl:41: :cowboy_handler.execute/2
        (cowboy) /c/Users/jtomc/Documents/Elixir/postit/deps/cowboy/src/cowboy_stream_h.erl:296: :cowboy_stream_h.execute/3
        (cowboy) /c/Users/jtomc/Documents/Elixir/postit/deps/cowboy/src/cowboy_stream_h.erl:274: :cowboy_stream_h.request_process/3
        (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3

Resources

basic blog tutorial

tutorial repo

Follow

Published 18 Jul 2019

A show about learning Elm, Functional Programing, and generally leveling up as a JS developer.
JavaScript To Elm on Twitter