I'm looking for a little help thinking through how we can balance security and UX for an open source web app.When our users deploy an application, we want them to be able to use it. But we don't necessarily want open registration - we'll want our first user to be in control through some sort of invite mechanism or by programmatically creating accounts.I think the best approach might be to use some combination of login, verify_account, and set password on verify?So after deploy thought we might create an account programmatically using an email address. Then email that user to verify the account and add a password.But it seems like the verify account depends on account create? It does seem I can verify programmatically created accounts, but even just enabling the feature adds the create-account route and form.
Alternatively perhaps we could use create_account, but would it be possible to only allow that functionality if there are 0 users in the DB?
I suppose we could also follow admin verification guide, and keep registration open?
Anyhow, feels like a great project, hoping we can figure out the best way to approach this! Thanks in advance for any ideas
I had a similar thought of what I would like to see in rodauth functionality. What about apps where only internal (company) users are allowed, would it make sense to sign up first user regular way, who would become administrator, then lock it for any other public signup and allow some kind of sign up by invitation only, where admin would generate and send invites who can sign up.
Thanks Jeremy, always a pleasure to use your software and receive such nice support!Thats a nice way to shut down registration after user 0.
I've made some progress here, but it seems like the verify_account feature doesn't have public methods for verifying the account when it was created programmatically?
I've got a little graphql mutation to invite a user -def resolve(email:, role:, oauth_client_id: nil)admin_user = Osso::Models::Account.new({email: email,status_id: 1,role: role,oauth_client_id: oauth_client_id,})if admin_user.savecontext[:rodauth].account_from_login(email)context[:rodauth].send_verify_account_emailreturn response_data(admin_user: admin_user)endresponse_error(admin_user.errors)end
seems to work well enough, but then the emailed verification link doesn't include a full token, just the account-ID_.
> If you created this account, please go to http://localhost:9292/verify-account?key=b7a02621-2099-4304-b267-d587a6df43c4_ to verify the account.I am creating a verification key myself and associating it with the account, but since the feature depends on the instance var @verify_account_key_value which doesn't have a public setter then the email won't use the DB value.Would making the setup_account_verification method public be a reasonable change? Is there a better way to hook in to the after_create_account for programmatically created accounts? IIRC Sequel eschews AR-style callbacks, so I don't think using AR instead of Sequel here makes much of a difference.
some other things ended up sneaking into this, but here's the PR where we added Rodauth, replacing a JWT auth system we rolled ourselves -super pleased with how things turned out!
can we add ourselves to the list of projects using Rodauth?
I've got one last task here that's seeming pretty difficult. Perhaps not, but I'm having a hard time following some of the meta-programming things. Admittedly this is also a bit outside the scope of Rodauth i think, I've gotten lucky so far to be able to get this far.I want to now create a user and send a verification email in a Rake task, but things break down for me at the sending of the verification email where I'm unable to provide templating methods.rodauth = Osso::Admin.rodauth.new(Class.new)account = rodauth.account_from_login(admin_email)rodauth.setup_account_verification=> NoMethodError (undefined method `parse_template_opts' for #<Class:0x00007fbc7559f568>)
It feels like the scope arg to the Rodauth initializer wants an instance of a class that defines a bunch of templating methods. I'm using the Roda render plugin.
I've tried some things like this, but no matter what I've tried I can't get rodauth's scope to match whats going on in the Roda app itself, and haven't gotten emails to send.class Fakeinclude Roda::RodaPlugins::Renderdef initializeRoda::RodaPlugins::Render.configure(Osso::Admin)end
endrodauth = Osso::Admin.rodauth.new(Fake.new)account = rodauth.account_from_login(admin_email)rodauth.setup_account_verificationAgain, I totally understand that doing this all in a Rake task and outside of a request / response cycle is not what this functionality is intended for, but any tips to get this solved would be much appreciated! It does feel like the hash returned by Roda::RodaPlugins::Render.configure(Osso::Admin) has what Rodauth needs to create the email template, but im missing something.
Perfect!
Without any hash entries, both the sender domain and base url aren't set, which makes sense since those are read off of the request object.
I am already requiring BASE_URL as an env var, so i can specify those in the rodauth config block no problem:
plugin :rodauth doenddomain URI.parse(ENV['BASE_URL']).hostbase_url ENV['BASE_URL']
but I haven't yet figured out how I can pass values into this constructor that allow request.host and request.base_url to return the proper values. I triedrodauth = Osso::Admin.rodauth.new(Osso::Admin.new({request: {base_url: ENV['BASE_URL'],host: URI.parse(ENV['BASE_URL']).host,}}))as well as using the rodauth auth_value_method name as the key likerodauth = Osso::Admin.rodauth.new(Osso::Admin.new({base_url: ENV['BASE_URL'],domain: URI.parse(ENV['BASE_URL']).host,}))
I'm happy with the rodauth block solution, but figured I'd ask.
I can't seem to figure out how to customize the email_from here.rodauth = Osso::Admin.rodauth.new(Osso::Admin.new({'HTTP_HOST' => base_uri.host,'PATH_INFO' => '/','SERVER_NAME' => base_uri.to_s,'rack.url_scheme' => base_uri.scheme,}))plugin :rodauth doenable :login, :verify_accountemail_from "Osso <no-reply@#{domain}>"