Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions app-rails/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,15 @@ To run natively:
1. `make start-native`
1. Then visit http://localhost:3100

#### Local Authentication

To simplify local development, you can log in using the credentials below—just make sure your environment is set to `development` and the `COGNITO_CLIENT_SECRET` is left empty:

```
email: "dev@example.com"
password: "password"
```

#### IDE tips

<details>
Expand Down
43 changes: 43 additions & 0 deletions app-rails/app/adapters/auth/local_adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
class Auth::LocalAdapter
def initialize
# In-memory user store, no database interaction here
@users = [
{ email: "dev@example.com", password: "password", confirmed: true }
]
end

def initiate_auth(email, password)
# Find the user in the in-memory list
user = @users.find { |u| u[:email] == email }

# If no user is found, simulate user creation
if user.nil?
Rails.logger.info "Simulating creation of new user for email: #{email}"

# Add the new user to the in-memory users array (no DB interaction)
user = { email: email, password: password, confirmed: true }

# Simulate adding the user to the array
@users << user
end

# Check if the password matches
if user[:password] != password
raise Auth::Errors::InvalidCredentials.new("Incorrect password")
elsif !user[:confirmed]
raise Auth::Errors::UserNotConfirmed.new("User not confirmed")
end

# Simulate a successful auth response
{
uid: "local-dev-user-uid",
provider: "local",
token: generate_token(user)
}
end

def generate_token(user)
# Simulate token generation (JWT or other logic)
JWT.encode({ user_id: user[:email], exp: 24.hours.from_now.to_i }, "secret_key")
end
end
2 changes: 1 addition & 1 deletion app-rails/app/controllers/users/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def auth_service

def new_session_params
# If :users_new_session_form is renamed, make sure to also update it in
# cognito_authenticatable.rb otherwise login will not work.
# auth_service_authenticatable.rb otherwise login will not work.
params.require(:users_new_session_form).permit(:email, :password, :spam_trap)
end

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# This adds a :cognito_authenticatable accessor for use in the `devise` portion of a user model
# This adds a :auth_service_authenticatable accessor for use in the `devise` portion of a user model
# Heavily inspired by https://www.endpointdev.com/blog/2023/01/using-devise-for-authentication-without-database-stored-accounts/
module Devise
module Models
module CognitoAuthenticatable
module AuthServiceAuthenticatable
extend ActiveSupport::Concern

module ClassMethods
Expand Down
2 changes: 1 addition & 1 deletion app-rails/app/models/user.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class User < ApplicationRecord
devise :cognito_authenticatable, :timeoutable
devise :auth_service_authenticatable, :timeoutable
attr_accessor :access_token

# == Enums ========================================================
Expand Down
14 changes: 12 additions & 2 deletions app-rails/app/services/auth_service.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
# frozen_string_literal: true

class AuthService
def initialize(auth_adapter = Auth::CognitoAdapter.new)
@auth_adapter = auth_adapter
def initialize(auth_adapter = nil)
@auth_adapter = auth_adapter || default_adapter
end

def default_adapter
return Auth::MockAdapter.new if Rails.env.test?

if Rails.env.development? && ENV["COGNITO_CLIENT_SECRET"].to_s.empty?
Auth::LocalAdapter.new
else
Auth::CognitoAdapter.new
end
end

# Send a confirmation code that's required to change the user's password
Expand Down
2 changes: 1 addition & 1 deletion app-rails/config/initializers/devise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Many of these configuration options can be set straight in your model.
Devise.setup do |config|
# ==> Support AWS Cognito login
Devise.add_module :cognito_authenticatable, controller: :sessions, route: :session
Devise.add_module :auth_service_authenticatable, controller: :sessions, route: :session

# ==> Configuration for :timeoutable
# The time you want to timeout the user session without activity. After this
Expand Down
Loading