Code Monkey home page Code Monkey logo

sentinel's Introduction

Sentinel

Build Status

Note

Currently master (this readme) and the latest hex release have diverged due to poor planning on my part while working on the next version of Sentinel. It also currently interacts poorly with the new directory structure of Phoenix 1.3. I'm currently working on an update to remedy this, but cannot promise it will be released soon.

If you'd like to assist in developing the latest version of Sentinel please reach out to me.

Things I wish Guardian included out of the box, like Ueberauth integration, routing, invitation flow, confirmation emails, and, password reset emails. It's just a thin wrapper on Guardian but everybody shouldn't have to roll this themselves when they build stuff.

I do my best to follow semantic versioning with this repo.

Suggestions? See the Contributing/Want something new? section.

Want an example app? Checkout Sentinel Example.

Installation

Here's how to add it to your Phoenix project, and things you need to setup:

# mix.exs

# Requires Elixir ~> 1.3

defp deps do
  # ...
  {:sentinel, "~> 2.0"},
  {:guardian_db, "~> 0.8.0"}, # If you'd like to database back your tokens, and prevent replayability
  # ...
end

Configure Guardian

Example config:

# config/config.exs

config :guardian, Guardian,
  allowed_algos: ["HS512"], # optional
  verify_module: Guardian.JWT,  # optional
  issuer: "MyApp",
  ttl: { 30, :days },
  verify_issuer: true, # optional
  secret_key: "guardian_sekret",
  serializer: Sentinel.GuardianSerializer,
  hooks: GuardianDb # optional if using guardiandb

More info

Optionally Configure GuardianDb

config :guardian_db, GuardianDb,
  repo: MyApp.Repo

The install task which ships with Sentinel, which you will run later in this walkthrough, creates the migration for the GuardianDb tokens.

Configure Sentinel

# config/config.exs

config :sentinel,
  app_name: "Test App",
  user_model: Sentinel.User, # should be your generated model
  send_address: "[email protected]",
  crypto_provider: Comeonin.Bcrypt,
  repo: Sentinel.TestRepo,
  ecto_repos: [Sentinel.TestRepo],
  auth_handler: Sentinel.AuthHandler,
  layout_view: MyApp.Layout, # your layout
  layout: :app,
  views: %{
    email: Sentinel.EmailView, # your email view (optional)
    error: Sentinel.ErrorView, # your error view (optional)
    password: Sentinel.PasswordView, # your password view (optional)
    session: Sentinel.SessionView, # your session view (optional)
    shared: Sentinel.SharedView, # your shared view (optional)
    user: Sentinel.UserView # your user view (optional)
  },
  router: Sentinel.TestRouter, # your router
  endpoint: Sentinel.Endpoint, # your endpoint
  invitable: true,
  invitation_registration_url: "http://localhost:4000", # for api usage only
  confirmable: :optional,
  confirmable_redirect_url: "http://localhost:4000", # for api usage only
  password_reset_url: "http://localhost:4000", # for api usage only
  send_emails: true,
  user_model_validator: {MyApp.Accounts, :custom_changeset}, # your custom validator
  registrator_callback: {MyApp.Accounts, :setup} # your callback function (optional)

See config/test.exs for an example of configuring Sentinel

invitation_registration_url, confirmable_redirect_url, and password_reset_url are three configuration settings that must be set if using the API routing in order to have some place to be directed to after completing the relevant server action. In most cases I'd anticipate this being a page of a SPA, Mobile App, or other client interface.

Configure Ueberauth

# config/config.exs

config :ueberauth, Ueberauth,
  providers: [
    identity: {
      Ueberauth.Strategy.Identity,
      [
        param_nesting: "user",
        callback_methods: ["POST"]
      ]
    },
  ]

Currently Sentinel is designed in such a way that the Identity Strategy must set params_nesting as "user". This is something that I would like to modify in future versions.

You'd also want to add other Ueberauth provider configurations at this point, as described in the respective provider documentation.

Configure Bamboo Mailer

# config/config.exs

config :sentinel, Sentinel.Mailer,
  adapter: Bamboo.TestAdapter

More info

Run the install Mix task

Create the database using Ecto if it doesn't yet exist.

mix sentinel.install

This will create a user model if it doesn't already exist, add a migration for GuardianDb migration, and add a migration for Ueberauth provider credentials.

You will want to delete the GuardianDb migration if you're choosing not to use it.

Currently the install task outputs the following warning:

warning: the :datetime type in migrations is deprecated, please use
:utc_datetime or :naive_datetime instead

This is due to the fact that Phoenix's generators don't appear to support utc_datetime being passed in. Please modify the generated migration accordingly. Phoenix's generators also appear to not support setting null: false with the migration generator, so you will want to set that in the migration for the user email as well.

Mount the desired routes

defmodule MyApp.Router do
  use MyApp.Web, :router
  require Sentinel

  # ...
  # ...

  scope "/" do
    # pipe_through, browser, api, or your own pipeline depending on your needs
    # pipe_through :browser
    # pipe_through :api
    Sentinel.mount_ueberauth
  end

  scope "/" do
    pipe_through :browser
    Sentinel.mount_html
  end

  scope "/api", as: :api do
    pipe_through :api
    Sentinel.mount_api
  end
end

Be aware that the routes mounted by the macro Sentinel.mount_ueberauth must be mounted on the root of your URL, due to the way Ueberauth matches against routes. To illustrate, the route for requesting a given provider must be example.com/auth/:provider. If it is example.com/api/auth/:provider Ueberauth will not properly register requests.

NOTE: You will run into an issue here if you set the scope to scope "/", MyApp.Router do.

The generated routes are shown in /lib/sentinel.ex:

Sentinel.mount_ueberauth

method path description
GET /login Login page
GET /logout Request logout
GET /auth/session/new Login page
POST /auth/session Request authentication
DELETE /auth/session Request logout
GET /auth/:provider Request specific Ueberauth provider login page
GET /auth/:provider/callback Callback URL for Ueberauth provider
POST /auth/:provider/callback Callback URL for Ueberauth provider

Sentinel.mount_html

method path description
GET /user/new New user page
POST /user Create new user
GET /user/:id/invited Invited user registration form
PUT /user/:id/invited Complete user invitation flow
GET /user/confirmation_instructions Request resending confirmation instructions page
POST /user/confirmation_instructions Request confirmation instructions email
GET /user/confirmation Confirm user email address from email
GET /password/new Forgot password page
POST /password/new Request password reset email
GET /password/edit Password reset page
PUT /password Reset password
GET /account Basic user edit page
PUT /account Update user information

Sentinel.mount_api

method path description
GET /user/:id/invited Redirect user from email link to invited user registration form
PUT /user/:id/invited Complete user invitation flow
GET /user/confirmation_instructions Request resending confirmation instructions
GET /user/confirmation Confirm user email address from email
GET /password/new Request password reset email
GET /password/edit Request password reset page from email
PUT /password Reset password
GET /account Requests user account
PUT /account Update user information
PUT /account/password Update user password separately

Overriding the Defaults

Confirmable

By default users are not required to confirm their account to login. If you'd like to require confirmation set the confirmable configuration field to :required. If you don't want confirmation emails sent, set the field to :false. The default is :optional.

Invitable

By default, users are required to have a password upon creation. If you'd like to enable users to create accounts on behalf of other users without a password you can set the invitable configuration field to true. This will result in the user being sent an email with a link to GET users/:id/invited, which you can complete by posting to the same URL, with the following params:

{
  "confirmation_token": "confirmation_token_from_email_provided_as_url_param",
  "password_reset_token": "password_reset_token_from_email_provided_as_url_param",
  "password": "newly_defined_user_password"
}

Custom Routes

If you want to customize the routes, or use your own controller endpoints you can do that by overriding the individual routes listed.

Generate custom views

If you want to use custom views, you'll need copy over the views and templates to your application. Sentinel provides a mix task make this a one-liner:

mix sentinel.gen.views

This mix task accepts a single argument of the specific context. This value can be "email", "error", "password", "session", "shared", or "user". Once you copy over a context's view and templates, you must update the config to point to your application's local files:

config :sentinel, views: %{user: MyApp.Web.UserView}

The keys for this views config map correspond with the list of contexts above.

Auth Error Handler

If you'd like to write your own custom authorization or authentication handler change the auth_handler Sentinel configuration option to the module name of your handler.

It must define two functions, unauthorized/2, and unauthenticated/2, where the first parameter is the connection, and the second is information about the session.

Custom model validator

If you want to add custom changeset validations to the user model, you can do that by specifying a user model validator:

config :sentinel, user_model_validator: {MyApp.Accounts, :custom_changeset}

This function must accept 2 arguments consisting of a changeset and a map of params and must return a changeset. The params in the second argument will be the raw params from the original request (not the ueberauth callback params).

def custom_changeset(changeset, attrs \\ %{}) do
  changeset
  |> cast(attrs, [:my_attr])
  |> validate_required([:my_attr])
  |> validate_inclusion(:my_attr, ["foo", "bar"])
end

Contributing/Want something new?

Create an issue. Preferably with a PR. If you're super awesome include tests.

As you recall from the license, this is provided as is. I don't make any money on this, so I do support when I feel like it. That said, I want to do my best to contribute to the Elixir/Phoenix community, so I'll do what I can.

Having said that if you bother to put up a PR I'll take a look, and either merge it, or let you know what needs to change before I do. Having experienced sending in PRs and never hearing anything about them, I know it sucks.

sentinel's People

Contributors

britton-jb avatar demijade avatar draiken avatar sahrizvi avatar termoose avatar tigerwolf avatar trestrantham avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sentinel's Issues

HTML views

Currently working on getting some base HTML views up, inspired by those packaged in Devise. This is a feature set requested from a number of people, and makes sense for the large Phoenix ecosystem.

Disable confirmation

How do I proceed so that a registration already starts confirmed and the user logged in?

I ended up creating everything with the --confirmation option, but I do not need it any more.

Error while visiting sentinel paths

Hi! I'm trying to use sentinel library. I've configured application using your configuration guide and sentinel_example project, but I'm getting errors when visiting paths like /login, /user/create and others provided by sentinel. Error looks this way: (UndefinedFunctionError) function :app.render/2 is undefined (module :app is not available). I will be very grateful for every suggestion.

Custom Model integration

Hi,

I want to add extra field during the signup like username, and I don't know how to handle this.

I tried creating my own controller and calling Sentinel function, and also trying to replace the :callback attribute in the view by my own function without success.

The "/user/new" work great, but I want to use sentinel on my own "/signup" with username/email/password field.

I would like to know how I could achieve that.

Thanks

Compilation error on file web/router.ex ==

When applying the routes as per the README:

defmodule` MyApp.Router do
  use MyApp.Web, :router
  require Sentinel
 

 pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
   
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/" do
    pipe_through :ueberauth
    Sentinel.mount_ueberauth
  end

  scope "/" do
    pipe_through :browser
    Sentinel.mount_html
  end

  scope "/api", as: :api do
    pipe_through :api
    Sentinel.mount_api
  end

end
== Compilation error on file web/router.ex ==
** (CompileError) web/router.ex:1: undefined function ueberauth/2
    (stdlib) lists.erl:1338: :lists.foreach/2
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
    (elixir) lib/kernel/parallel_compiler.ex:117: anonymous fn/4 in Kernel.ParallelCompiler.spawn_compilers/1

As per the instructions ueberauth is set as an application.

When commenting out:

#scope "/" do
  #  pipe_through :ueberauth
  #  Sentinel.mount_ueberauth
  #end

The compiling error goes away.

Testing with:

defmodule MyApp.Router do
  use MyApp.Web, :router
  require Sentinel
 

 pipeline :browser do
    plug Ueberauth
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
   
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  #scope "/" do
  #  pipe_through :ueberauth
  #  Sentinel.mount_ueberauth
  #end

  scope "/" do
    pipe_through :browser
    Sentinel.mount_html
    Sentinel.mount_ueberauth
  end

  scope "/api", as: :api do
    pipe_through :api
    Sentinel.mount_api
  end

end

When running mix sentinel.install

When running mix sentinel.install mix shows the following error:

  • (File.Error) could not stream "deps/sentinel/test/support/migrations/guardian_db_migration.exs": no such file or directory
    (elixir) lib/file/stream.ex:78: anonymous fn/2 in Enumerable.File.Stream.reduce/3
    (elixir) lib/stream.ex:1240: anonymous fn/5 in Stream.resource/3
    (elixir) lib/enum.ex:1767: Enum.map/2
    lib/mix/tasks/install.ex:111: Mix.Tasks.Sentinel.Install.generate_token_migration/0
    lib/mix/tasks/install.ex:28: Mix.Tasks.Sentinel.Install.create_migrations/0
    lib/mix/tasks/install.ex:11: Mix.Tasks.Sentinel.Install.run/1
    (mix) lib/mix/task.ex:294: Mix.Task.run_task/3
    (mix) lib/mix/cli.ex:58: Mix.CLI.run_task/2
    (elixir) lib/code.ex:370: Code.require_file/2

When using github as the package source in mix deps it works fine.

Tests for HTML controllers

Both the Users and the Sessions controllers have been recently introduced, but have been frustratingly buggy to work with. Small errors like mismatched parameters, lost error messages, wrong redirects, etc.

I think specially since this part is supposed to be integrated with an external application and some customizeable parts (eg. views) they need more robust tests.

Providing a default that Just Works is very important

Not sure if you want integration tests or more specialized ones, but either way all the boundaries need to be tested. With that it'll be easier to document how you can extend and customize Sentinel too.

Edit: wording

example sentinel app

Thank you for all this!

It would be great to have an example Sentinel 2.0 app.

Kind regards,

Angel

Ability to generate controllers and views during installation

While I appreciate the "everything but the kitchen sink" approach of this library, I think the inner workings are a bit too opaque.

I think being able to generate one's own controllers and views during installation would go a long way towards customizability.

For example, new user creation via a JSON api seems to be handled through JSON.UserController, but it follows invitation logic where the user provides their email first, confirms it, then creates their password.

What if I want to have the user provide their email AND password during the first step? Currently there isn't a way to do that (unless I missed something - documentation and examples assume too much prior knowledge of Guardian and UeberAuth).

Ueberauth

On the back burner until I wrap up the HTML views, but I'd like to add ueberauth functionality out of the box as well.

with statement in Sentinel.Controllers.Html.AuthController.new_user has no else clause

The with statement in Sentinel.Controllers.Html.AuthController.new_user() has no else clause. This leads to the following exceedingly cryptic error message if AfterRegistrator.confirmable_and_invitable() or RegistratorHelper.callback() fails to return {:ok, user}.

expected action/2 to return a Plug.Conn, all plugs must receive a connection (conn) and return a connection

Error compiling - no function clause matching in Keyword.merge/2

Im getting this error when I tried upgrading Sentinel from 1 to 2.

== Compilation error on file lib/sentinel/web/controllers/auth_controller.ex ==
** (FunctionClauseError) no function clause matching in Keyword.merge/2
    (elixir) lib/keyword.ex:579: Keyword.merge(nil, [])
    lib/ueberauth.ex:175: Ueberauth.init/1
    (plug) lib/plug/builder.ex:193: Plug.Builder.init_module_plug/3
    (plug) lib/plug/builder.ex:181: anonymous fn/4 in Plug.Builder.compile/3
    (elixir) lib/enum.ex:1755: Enum."-reduce/3-lists^foldl/2-0-"/3
    (plug) lib/plug/builder.ex:181: Plug.Builder.compile/3
    (phoenix) expanding macro: Phoenix.Controller.Pipeline.__before_compile__/1
    lib/sentinel/web/controllers/auth_controller.ex:1: Sentinel.Controllers.AuthController (module)
    (elixir) lib/kernel/parallel_compiler.ex:117: anonymous fn/4 in Kernel.ParallelCompiler.spawn_compilers/1

I tried to narrow down where the error was being caused and had trouble making any in-roads.

UserView Layouts

Hi there!

More of a question than an issue, but exhausted my google searches trying to find a solution and you may know this already.

I provide a Phoenix.View object on Sentinel's configuration. It works finding the template, but I could not find a way to add my application layout to it.
Since normally the controller adds the layout, and the controller is on Sentinel, not my application, the only place I could add it is in the view.

My idea was to match the render method, add the layout and call upstream's render. Problem is, the layout key is not in the map.

def render("new.html", assigns), do: # add layout and call render again.

If I use the above, it's going to loop. My initial idea was to pattern match when the key is NOT there, but either I'm bad at google or there isn't a way to do that.

The second option, to render the template myself, also doesn't work since the render method is the last one in the public API of phoenix's view.

My last instinct was to just "override" the controller method. That would mean I'd need to have the Sentinel controller as a behavior that I could override the methods myself. Using that I'm guessing the layout will already be set by use App.Web, :controller. But this is coming from someone with OO centric views, so this may be horrible or not even possible.

Would appreciate to hear any of your thoughts on this

Thanks!

Separate User & Auth models / tables

This is a design suggestion.

When you store everything in one table it will work, but its not extendable for further scenarios.
I would suggest to create a separate auth table and a separate user table.

Pros:

  1. An user is able to use multiple auth strategies. like facebook / google / email / others..
  2. The user model does not depend on a authentication strategy
  3. Clean separation, cleaner models

Mix task

I'd like to add a mix task that does all of the basic configuration and setup of sentinel from a fresh phoenix app.

Ecto 2

Need to update to use Ecto 2

Guardian V1 Support

Hi

I've been working on getting a release together for Guardian v1. This release is
significantly different (in a good way!).

The big difference in V1 is the use of an implementation module, allowing for
multiple configurations per project.

Guardian V1 allows for:

  • Supporting token types other than JWT
  • Supporting multiple configurations in a single project
  • Pipelining of Guardian plugs
  • Extracting phoenix helpers into a different project
  • Better hooking Support
  • Moves the serializer into the implementation module

To get started with V1 developers need to create a 'token module'.

  defmodule MyApp.AuthTokens do
    use Guardian, otp_app: :my_app

    def subject_for_token(resource, _claims), do: to_string(resource.id)
    def resource_from_claims(claims) do
      find_me_a_resource(claims["sub"])
    end
  end

Once you have your implementation module (a bare bones one is above) you can use that directly:

MyApp.AuthTokens.encode_and_sign(resource, claims, opts)
MyApp.AuthTokens.decode_and_verify(token, claims_to_check, opts)

Or, for library authors such as yourself

Guardian.encode_and_sign(MyApp.AuthTokens, resource, claims, opts)
Guardian.decode_and_verify(MyApp.AuthTokens, token, claims_to_check, opts)

We've also disambiguated setting token type, ttl and the key from the claims. These are now set via the options.

Guardian.encode_and_sign(MyApp.AuthTokens, resource, claims, token_type: "access", key: :secret, ttl: {1, :week})

Secrets and configuration values also got an overhaul. Any value can be of the form:

  • {:system, "KEY"}
  • {mod, :func}
  • {mod, :func, [args]}
  • fn -> some_value end
  • or a literal value

These configuration options can be set either in the configuration or in the implementation module as options to use Guardian

Pipelines

All plugs require being set as part of a pipeline. Pipelines put the implementation module and error handler on the conn.

You can set these directly with Guardian.Pipeline or create a pipeline module

plug Guardian.Pipeline, module: MyApp.AuthTokens, error_handler: MyApp.AuthErrorHandler

OR

  defmodule MyApp.AuthPipeline do
    use Guardian.Plug.Pipeline, otp_app: :my_app,
                                module: MyApp.Tokens,
                                error_handler: MyApp.AuthErrorHandler

    alias Guardian.Plug.{
      EnsureAuthenticated,
      LoadResource,
      VerifySession,
      VerifyHeader,
    }

    plug VerifySession, claims: @claims
    plug VerifyHeader, claims: @claims, realm: "Bearer"
    plug EnsureAuthenticated
    plug LoadResource, ensure: true
  end

With usage

plug MyApp.AuthPipeline

I expect that this will be a pre-release within about a week.
I'd love to get feedback on it before it goes full version 1.

2.0.0rc

Currently testing HTML and JSON for the 2.0.0rc, available here as the v2 branch.

Fixed issue with improper session verification using Guardian plugs in most recent commit. Working through ensuring there are no other issues.

Given the way it looks to be performing we should have a 2.0.0 official release by next Monday.

** (Mix) The task "sentinel.gen.views" could not be found

Maybe I missed something important, but the instructions and source code seem to indicate the mix task sentinel.gen.views should exist. I get the following error when I try to use it.

** (Mix) The task "sentinel.gen.views" could not be found

The task does not exist in deps/sentinel/lib/mix/tasks/.

Registerable

Break registerable out into it's own module that can be switched on and off. Some users may not want users to be able to register for their application on their own.

This should just be a config option that then removes the new user page in the router mount macro.

Ueberauth JSON API

Currently the identity provider will work as intended on the JSON, but the Ueberauth provider flow has a few sticking points, related to this discussion.

In my testing I'm able to properly implement the OAuth flow, and redirect the user back to the single page application, the current intended use case, but then getting a guardian token down to the client securely is proving problematic. Currently it looks like the best way to handle this would either by using the session, or by appending it the URL, the latter seeming like a very bad idea, and the former seeming a bit difficult for the API user.

Currently due to constraints in Ueberauth (referenced in the above discussion) this also will not handle a mobile app authenticating using for example Google and attempting to pass the token back to the server. It looks like the better way to handle this use case may be to use another OAuth library in tandem to authenticate using a token gathered by the client OAuth flow to generate a Guardian token.

Currently open to advice and suggestions, as I feel I may be missing something obvious here.

Lockable and example app

Hi!
I'm reviewing this for a project. I wonder if you already have an example app done.

Maybe I could help with that. I don't know if this is what I need yet, or whether will work with what I have already done. It's a Phoenix app with React.js front-end.

Currently, there are features here that I don't need and it's missing what I need: #9 Lockable.

I have not looked into how this was done in Devise, but I guess you need failed_attempts and locked_at fields

https://github.com/katgironpe/rails_api_template/blob/master/db/schema.rb

Token Customization

Guardian.Plug.sign_in(user) calls appear in a number of places in few files. As of now, there does not appear to be a way to add permissions or otherwise customize generated tokens.

Maybe a solution would be factoring these calls out into something like a TokenMint module?

defmodule TokenMint do
  def sign_in(conn, user), do: Guardian.Plug.sign_in(conn, user)
end

A configuration option could be used to replace this with a user supplied module/function/plug that takes the user and uses it to mint a customized token. Would this be a reasonable way of issuing customized tokens in Sentinel?

Multiple User Types

Allow Sentinel to work with multiple model types, for example a regular user, and an admin user.

Probably not going to get to this until after Ueberauth integration, which will be V2.

Issues using with phoenix 1.3.0

New to phoenix, trying this out. I see in the README that you are upgrading, so perhaps this bug report is useless, but following along with the README to integrate sentinel with a test phoenix app I have I hit the following warning:

mix phoenix.gen.model is deprecated. Use phx.gen.schema instead.

Looking through the code, it seems this is still in the master branch at https://github.com/britton-jb/sentinel/blob/master/lib/mix/tasks/install.ex#L52.

I'd offer to help out with that, but I'm new to elixir/phoenix and probably would be more noise than signal. (I don't even know how to install the local cloned version of this app in favor of the one from hex.pm, for example)

Email bodies are blank

Trying to use sentinel for invitations, I've been trying for quite awhile to get this working. At first the emails weren't sending at all, but I figured out the send_emails param and after setting that emails are sending but the email body is blank for both html and text formats.

This is my config:

config :guardian, Guardian,
  issuer: "MyApp",
  ttl: { 30, :days },
  verify_issuer: true,
  secret_key: System.get_env("SECRET_KEY"),
  serializer: MyApp.GuardianSerializer

config :guardian_db, GuardianDb,
  repo: MyApp.Repo

config :sentinel,
  app_name: "MyApp",
  user_model: MyApp.User,
  email_sender: "support@my_app.com",
  crypto_provider: Comeonin.Bcrypt,
  repo: MyApp.Repo,
  invitable: :true,
  endpoint: MyApp.Endpoint,
  router: MyApp.Router,
  send_emails: true,
  environment: :development

config :sentinel, Sentinel.Mailer,
  adapter: Bamboo.LocalAdapter

config :my_app, MyApp.Mailer,
  adapter: Bamboo.LocalAdapter

This is how I'm triggering it:

Sentinel.UserRegistration.register(%{ "user" => %{ "email" => email } })

UserView documentation.

The documentation example settings list user_view: MyApp.UserModel.View,. I had to change this to user_view: MyApp.UserView, to get Sentinel to work.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.