From a6d8790ecdeb1f9624149aa39786f81e266d2eab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20Verg=C3=A9s?= <ivan@platoniq.net>
Date: Fri, 28 May 2021 15:48:26 +0200
Subject: [PATCH] Introduce a module for ephemeral participation and a
 integrated Census+SMS verification (#368)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* ignore capistrano files

* add letter opener to production

* Update to latest revision and add locales

* PB05 (#1)

* Use custom fork of decidim and feature branch

* Change branch to PB05

* Update to latest revision

* Update and add locales

* Upate to latest revision

* Update revision

* Update to alt branch

* Update to latest revision

* Update to latest revision (focus mode compatible with banners)

* Reorganize information for budget summary + back link

* Merge PB03

* Fix progress bar text for mobile

* Point decidim to main dev branch

* Remove locales that should come from decidim repo

* Update to AjuntamentdeBarcelona/decidim#6

* Change budgets progress bar color (#5)

* Add translations

* Chnage progress bar color

* Hide follow button for projects

* PB01 - Introduce a new module to enable ephemeral participation in Decidim (#3)

* Introduce a new module to enable ephemeral participation in Decidim

- System configuration for verification handlers
- Component global flag for ephemeral verification
- Budgets tweaks to allow ephemeral verification
- User after-registration journey

* Update unauthorized_ephemeral_participant_message

* Fix decidim/budgets/projects/project_budget_button partial (2)

* Ephemeral participation part 3 (#3)

* Add some commands

* Forbid ephemeral users with verification conflicts to complete registration

* Fix bug

* Update README

* Ephemeral participation part 4 (#4)

* Change progress bar color

* add a default nickname when creating a ephemeral user

* fit i18n copies scopes. fix newly creating organizations without authorizations

* fix 2020 budget workflow

* Bad commit message

Co-authored-by: Vera Rojman <vrojman@protonmail.com>

* Census + SMS verification workflow (#4)

* Stub census + sms verification

* Fix rubocop offenses

* Initialize workflow when sms_gateway variables present

* Remove 'byebug'

* Prevent error with date_of_birth

* Add options for districts in verification

* Don't require scope in verification

* Send sms code after successful census verification

* Fix district keys

* Update translations

* Comment sms code delivery for testing purposes

* Add custom ActionAuthorizer for verification scope (district)

* Simplify redirection on successful verification

* Move form fields into view

* Add styles

* Improve locales

* Improve design

* Improve layout

* Allow users to reset verification code

* Sanitize document number

* Add help link for postal code

* Add system spec for authorization

* some copies. new budget workflow. fix test

* config secrets for test

Co-authored-by: Ivan Vergés <ivan@platoniq.net>

* Fix PB01 Details (#7)

* Fix typo

* Update gemfile

* Fix available_authorizations when stored as array

* Hide radio button for worfklows not available for ephemeral

* Fix class name

* enable new verificator for ephemeral participation

Co-authored-by: Vera Rojman <vrojman@protonmail.com>
Co-authored-by: Vera Rojman <vera@platoniq.net>
---
 .gitignore                                    |   2 +
 .rubocop.yml                                  |  34 ++---
 Gemfile                                       |   8 +-
 Gemfile.lock                                  |  48 +++---
 app/assets/stylesheets/_barcelona.scss        |   1 +
 .../stylesheets/theme-barcelona/_budgets.scss |  11 ++
 app/services/census_authorization_handler.rb  |   8 +-
 config/initializers/decidim.rb                |  18 +++
 config/initializers/decidim_budgets.rb        |   2 +
 config/locales/ca.yml                         |   5 +-
 .../locales/decidim_budgets_workflows_ca.yml  |  11 ++
 .../locales/decidim_budgets_workflows_en.yml  |   2 +
 .../locales/decidim_budgets_workflows_es.yml  |  11 ++
 config/routes.rb                              |   2 +
 config/secrets.yml                            |   7 +
 ...zations.decidim_ephemeral_participation.rb |  41 +++++
 db/schema.rb                                  |   4 +-
 decidim-census_sms/README.md                  |  13 ++
 decidim-census_sms/Rakefile                   |   3 +
 .../config/decidim_census_sms_manifest.css    |   3 +
 .../decidim/census_sms/verification.scss      |  24 +++
 .../census_sms/verification/reset_code.rb     |  47 ++++++
 .../verification/authorizations_controller.rb | 115 ++++++++++++++
 .../verification/authorization_form.rb        |  75 ++++++++++
 .../census_sms/verification/reset_form.rb     |  47 ++++++
 .../verification/action_authorizer.rb         |  35 +++++
 .../verification/authorizations/edit.html.erb |  29 ++++
 .../verification/authorizations/new.html.erb  |  58 +++++++
 .../authorizations/reset.html.erb             |  23 +++
 decidim-census_sms/config/i18n-tasks.yml      |   2 +
 decidim-census_sms/config/locales/ca.yml      |  58 +++++++
 decidim-census_sms/config/locales/es.yml      |   5 +
 decidim-census_sms/decidim-census_sms.gemspec |  18 +++
 decidim-census_sms/lib/decidim/census_sms.rb  |   9 ++
 .../lib/decidim/census_sms/verification.rb    |  10 ++
 .../decidim/census_sms/verification/engine.rb |  29 ++++
 decidim-ephemeral_participation/README.md     |  44 ++++++
 .../project_list_item_cell_override.rb        |  14 ++
 .../create_ephemeral_participant.rb           |  81 ++++++++++
 .../destroy_ephemeral_participant.rb          |  46 ++++++
 .../transfer_ephemeral_participant.rb         |  47 ++++++
 .../transfer_user_override.rb                 |  23 +++
 .../update_ephemeral_participant.rb           |  51 +++++++
 .../ephemeral_participable.rb                 |  97 ++++++++++++
 .../needs_permission_override.rb              |  69 +++++++++
 .../application_controller_override.rb        |  14 ++
 .../conflicts_controller_override.rb          |  36 +++++
 .../ephemeral_participants_controller.rb      |  71 +++++++++
 .../component_form_override.rb                |  22 +++
 .../ephemeral_participant_form.rb             |  50 +++++++
 .../permissions_form_override.rb              |  54 +++++++
 .../transfer_user_form_override.rb            |  28 ++++
 .../update_organization_form_override.rb      |  43 ++++++
 .../component_override.rb                     |  31 ++++
 .../organization_override.rb                  |  22 +++
 .../permission_action_override.rb             |  15 ++
 .../ephemeral_participation/user_override.rb  |  48 ++++++
 ...ephemeral_action_permissions_dictionary.rb |  32 ++++
 .../ephemeral_participation_permissions.rb    | 112 ++++++++++++++
 .../permissions_override.rb                   |  24 +++
 .../flash_messages_presenter.rb               |  58 +++++++
 .../session_presenter.rb                      |  28 ++++
 .../duplicated_users.rb                       |  20 +++
 .../verification_conflicts.rb                 |  19 +++
 .../informing_recognizer.rb                   |  50 +++++++
 .../redirection_recognizer.rb                 |  46 ++++++
 .../projects/_project_budget_button.html.erb  |  46 ++++++
 .../ephemeral_participants/edit.html.erb      |  16 ++
 .../shared/_login_modal.erb                   |  30 ++++
 .../decidim/shared/_login_modal.html.erb      |  63 ++++++++
 .../_authorizations_settings.erb              |  61 ++++++++
 .../system/organizations/edit.html.erb        |  36 +++++
 .../decidim/system/organizations/new.html.erb |  77 ++++++++++
 .../views/layouts/decidim/_user_menu.html.erb |  24 +++
 .../_user_menu.html.erb                       |  40 +++++
 .../user_profile.html.erb                     |  31 ++++
 .../config/locales/ca.yml                     |  51 +++++++
 .../config/locales/en.yml                     |  51 +++++++
 .../config/locales/es.yml                     |  51 +++++++
 ..._organizations_available_authorizations.rb |  38 +++++
 .../decidim-ephemeral_participation.gemspec   |  18 +++
 .../lib/decidim/ephemeral_participation.rb    |   7 +
 .../decidim/ephemeral_participation/engine.rb |  46 ++++++
 ...erifications_workflow_manifest_override.rb |  22 +++
 .../valid_auth/authorizations_controller.rb   |   2 +-
 lib/budgets_workflow_pam2020.rb               |   4 +-
 lib/budgets_workflow_pam2021.rb               |  70 +++++++++
 spec/system/census16_authorization_spec.rb    |   2 +-
 spec/system/census_authorization_spec.rb      |   2 +-
 spec/system/census_sms_authorization_spec.rb  | 141 ++++++++++++++++++
 90 files changed, 2990 insertions(+), 52 deletions(-)
 create mode 100644 app/assets/stylesheets/theme-barcelona/_budgets.scss
 create mode 100644 config/locales/decidim_budgets_workflows_ca.yml
 create mode 100644 config/locales/decidim_budgets_workflows_es.yml
 create mode 100644 db/migrate/20210518204806_update_organizations_available_authorizations.decidim_ephemeral_participation.rb
 create mode 100644 decidim-census_sms/README.md
 create mode 100644 decidim-census_sms/Rakefile
 create mode 100644 decidim-census_sms/app/assets/config/decidim_census_sms_manifest.css
 create mode 100644 decidim-census_sms/app/assets/stylesheets/decidim/census_sms/verification.scss
 create mode 100644 decidim-census_sms/app/commands/decidim/census_sms/verification/reset_code.rb
 create mode 100644 decidim-census_sms/app/controllers/decidim/census_sms/verification/authorizations_controller.rb
 create mode 100644 decidim-census_sms/app/forms/decidim/census_sms/verification/authorization_form.rb
 create mode 100644 decidim-census_sms/app/forms/decidim/census_sms/verification/reset_form.rb
 create mode 100644 decidim-census_sms/app/services/decidim/census_sms/verification/action_authorizer.rb
 create mode 100644 decidim-census_sms/app/views/decidim/census_sms/verification/authorizations/edit.html.erb
 create mode 100644 decidim-census_sms/app/views/decidim/census_sms/verification/authorizations/new.html.erb
 create mode 100644 decidim-census_sms/app/views/decidim/census_sms/verification/authorizations/reset.html.erb
 create mode 100644 decidim-census_sms/config/i18n-tasks.yml
 create mode 100644 decidim-census_sms/config/locales/ca.yml
 create mode 100644 decidim-census_sms/config/locales/es.yml
 create mode 100644 decidim-census_sms/decidim-census_sms.gemspec
 create mode 100644 decidim-census_sms/lib/decidim/census_sms.rb
 create mode 100644 decidim-census_sms/lib/decidim/census_sms/verification.rb
 create mode 100644 decidim-census_sms/lib/decidim/census_sms/verification/engine.rb
 create mode 100644 decidim-ephemeral_participation/README.md
 create mode 100644 decidim-ephemeral_participation/app/cells/decidim/ephemeral_participation/project_list_item_cell_override.rb
 create mode 100644 decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/create_ephemeral_participant.rb
 create mode 100644 decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/destroy_ephemeral_participant.rb
 create mode 100644 decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/transfer_ephemeral_participant.rb
 create mode 100644 decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/transfer_user_override.rb
 create mode 100644 decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/update_ephemeral_participant.rb
 create mode 100644 decidim-ephemeral_participation/app/controllers/concerns/decidim/ephemeral_participation/ephemeral_participable.rb
 create mode 100644 decidim-ephemeral_participation/app/controllers/concerns/decidim/ephemeral_participation/needs_permission_override.rb
 create mode 100644 decidim-ephemeral_participation/app/controllers/decidim/ephemeral_participation/application_controller_override.rb
 create mode 100644 decidim-ephemeral_participation/app/controllers/decidim/ephemeral_participation/conflicts_controller_override.rb
 create mode 100644 decidim-ephemeral_participation/app/controllers/decidim/ephemeral_participation/ephemeral_participants_controller.rb
 create mode 100644 decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/component_form_override.rb
 create mode 100644 decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/ephemeral_participant_form.rb
 create mode 100644 decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/permissions_form_override.rb
 create mode 100644 decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/transfer_user_form_override.rb
 create mode 100644 decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/update_organization_form_override.rb
 create mode 100644 decidim-ephemeral_participation/app/models/decidim/ephemeral_participation/component_override.rb
 create mode 100644 decidim-ephemeral_participation/app/models/decidim/ephemeral_participation/organization_override.rb
 create mode 100644 decidim-ephemeral_participation/app/models/decidim/ephemeral_participation/permission_action_override.rb
 create mode 100644 decidim-ephemeral_participation/app/models/decidim/ephemeral_participation/user_override.rb
 create mode 100644 decidim-ephemeral_participation/app/permissions/decidim/ephemeral_participation/ephemeral_action_permissions_dictionary.rb
 create mode 100644 decidim-ephemeral_participation/app/permissions/decidim/ephemeral_participation/ephemeral_participation_permissions.rb
 create mode 100644 decidim-ephemeral_participation/app/permissions/decidim/ephemeral_participation/permissions_override.rb
 create mode 100644 decidim-ephemeral_participation/app/presenter/decidim/ephemeral_participation/flash_messages_presenter.rb
 create mode 100644 decidim-ephemeral_participation/app/presenter/decidim/ephemeral_participation/session_presenter.rb
 create mode 100644 decidim-ephemeral_participation/app/queries/decidim/ephemeral_participation/duplicated_users.rb
 create mode 100644 decidim-ephemeral_participation/app/queries/decidim/ephemeral_participation/verification_conflicts.rb
 create mode 100644 decidim-ephemeral_participation/app/services/decidim/ephemeral_participation/informing_recognizer.rb
 create mode 100644 decidim-ephemeral_participation/app/services/decidim/ephemeral_participation/redirection_recognizer.rb
 create mode 100644 decidim-ephemeral_participation/app/views/decidim/budgets/projects/_project_budget_button.html.erb
 create mode 100644 decidim-ephemeral_participation/app/views/decidim/ephemeral_participation/ephemeral_participants/edit.html.erb
 create mode 100644 decidim-ephemeral_participation/app/views/decidim/ephemeral_participation/shared/_login_modal.erb
 create mode 100644 decidim-ephemeral_participation/app/views/decidim/shared/_login_modal.html.erb
 create mode 100644 decidim-ephemeral_participation/app/views/decidim/system/organizations/_authorizations_settings.erb
 create mode 100644 decidim-ephemeral_participation/app/views/decidim/system/organizations/edit.html.erb
 create mode 100644 decidim-ephemeral_participation/app/views/decidim/system/organizations/new.html.erb
 create mode 100644 decidim-ephemeral_participation/app/views/layouts/decidim/_user_menu.html.erb
 create mode 100644 decidim-ephemeral_participation/app/views/layouts/decidim/ephemeral_participation/_user_menu.html.erb
 create mode 100644 decidim-ephemeral_participation/app/views/layouts/decidim/ephemeral_participation/user_profile.html.erb
 create mode 100644 decidim-ephemeral_participation/config/locales/ca.yml
 create mode 100644 decidim-ephemeral_participation/config/locales/en.yml
 create mode 100644 decidim-ephemeral_participation/config/locales/es.yml
 create mode 100644 decidim-ephemeral_participation/db/migrate/20210518192857_update_organizations_available_authorizations.rb
 create mode 100644 decidim-ephemeral_participation/decidim-ephemeral_participation.gemspec
 create mode 100644 decidim-ephemeral_participation/lib/decidim/ephemeral_participation.rb
 create mode 100644 decidim-ephemeral_participation/lib/decidim/ephemeral_participation/engine.rb
 create mode 100644 decidim-ephemeral_participation/lib/decidim/ephemeral_participation/verifications_workflow_manifest_override.rb
 create mode 100644 lib/budgets_workflow_pam2021.rb
 create mode 100644 spec/system/census_sms_authorization_spec.rb

diff --git a/.gitignore b/.gitignore
index c3262449f0..61d568b580 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,3 +25,5 @@
 /imports
 
 .rspec-failures
+Capfile
+config/deploy*
\ No newline at end of file
diff --git a/.rubocop.yml b/.rubocop.yml
index 66eabf9d2d..dca2cdbcb4 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -89,7 +89,7 @@ Style/Alias:
     - prefer_alias_method
 
 # Align the elements of a hash literal if they span more than one line.
-Layout/AlignHash:
+Layout/HashAlignment:
   # Alignment of entries using hash rocket as separator. Valid values are:
   #
   # key - left alignment of keys
@@ -152,7 +152,7 @@ Layout/AlignHash:
     - ignore_implicit
     - ignore_explicit
 
-Layout/AlignParameters:
+Layout/ParameterAlignment:
   # Alignment of parameters in multi-line method calls.
   #
   # The `with_first_parameter` style aligns the following lines along the same
@@ -263,20 +263,6 @@ Style/BlockDelimiters:
     - proc
     - it
 
-Style/BracesAroundHashParameters:
-  EnforcedStyle: no_braces
-  SupportedStyles:
-    # The `braces` style enforces braces around all method parameters that are
-    # hashes.
-    - braces
-    # The `no_braces` style checks that the last parameter doesn't have braces
-    # around it.
-    - no_braces
-    # The `context_dependent` style checks that the last parameter doesn't have
-    # braces around it, but requires braces if the second to last parameter is
-    # also a hash literal.
-    - context_dependent
-
 # Indentation of `when`.
 Layout/CaseIndentation:
   EnforcedStyle: case
@@ -469,7 +455,7 @@ Naming/FileName:
   # files with a shebang in the first line).
   IgnoreExecutableScripts: true
 
-Layout/IndentFirstArgument:
+Layout/FirstArgumentIndentation:
   EnforcedStyle: special_for_inner_method_call_in_parentheses
   SupportedStyles:
     # The first parameter should always be indented one step more than the
@@ -557,7 +543,7 @@ Layout/IndentationWidth:
   Width: 2
 
 # Checks the indentation of the first element in an array literal.
-Layout/IndentFirstArrayElement:
+Layout/FirstArrayElementIndentation:
   # The value `special_inside_parentheses` means that array literals with
   # brackets that have their opening bracket on the same line as a surrounding
   # opening round parenthesis, shall have their first element indented relative
@@ -579,13 +565,13 @@ Layout/IndentFirstArrayElement:
   IndentationWidth: ~
 
 # Checks the indentation of assignment RHS, when on a different line from LHS
-Layout/IndentAssignment:
+Layout/AssignmentIndentation:
   # By default, the indentation width from Style/IndentationWidth is used
   # But it can be overridden by setting this parameter
   IndentationWidth: ~
 
 # Checks the indentation of the first key in a hash literal.
-Layout/IndentFirstHashElement:
+Layout/FirstHashElementIndentation:
   # The value `special_inside_parentheses` means that hash literals with braces
   # that have their opening brace on the same line as a surrounding opening
   # round parenthesis, shall have their first key indented relative to the
@@ -792,12 +778,12 @@ Naming/PredicateName:
     - has_
     - have_
   # Predicate name prefixes that should be removed.
-  NamePrefixBlacklist:
+  ForbiddenPrefixes:
     - is_
     - have_
   # Predicate names which, despite having a blacklisted prefix, or no ?,
   # should still be accepted
-  NameWhitelist:
+  AllowedMethods:
     - is_a?
   # Exclude Rspec specs because there is a strong convetion to write spec
   # helpers in the form of `have_something` or `be_something`.
@@ -978,7 +964,7 @@ Style/TernaryParentheses:
     - require_no_parentheses
   AllowSafeAssignment: true
 
-Layout/TrailingBlankLines:
+Layout/TrailingEmptyLines:
   EnforcedStyle: final_newline
   SupportedStyles:
     - final_newline
@@ -1028,7 +1014,7 @@ Style/TrivialAccessors:
   # Commonly used in DSLs
   AllowDSLWriters: false
   IgnoreClassMethods: false
-  Whitelist:
+  AllowedMethods:
     - to_ary
     - to_a
     - to_c
diff --git a/Gemfile b/Gemfile
index babe32ea39..7a25ff3717 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,15 +1,19 @@
 source "https://rubygems.org"
 
-DECIDIM_VERSION = { git: "https://github.com/decidim/decidim", branch: "release/0.24-stable" }
+DECIDIM_MAIN_BRANCH = "feature/bcn-budget-v0.24"
+
+DECIDIM_VERSION = { git: "https://github.com/AjuntamentdeBarcelona/decidim", branch: DECIDIM_MAIN_BRANCH }.freeze
 
 ruby '2.7.2'
 
 gem "decidim", DECIDIM_VERSION
+gem "decidim-census_sms", path: "decidim-census_sms"
 gem "decidim-dataviz", path: "decidim-dataviz"
 gem "decidim-initiatives", DECIDIM_VERSION
 gem "decidim-sortitions", DECIDIM_VERSION
 gem "decidim-stats", path: "decidim-stats"
 gem "decidim-valid_auth", path: "decidim-valid_auth"
+gem "decidim-ephemeral_participation", path: "decidim-ephemeral_participation"
 gem "decidim-navigation_maps", "~> 1.2.0"
 
 # Change term_customizer dependency to ruby-gems' when term-customizer is compatible with DECIDIM_VERSION
@@ -49,6 +53,8 @@ group :development do
 end
 
 group :production do
+  # can be removed after
+  gem "letter_opener_web"
   gem "sidekiq"
   gem "rails_12factor"
   gem "fog-aws"
diff --git a/Gemfile.lock b/Gemfile.lock
index 7fbb8509da..1af85f82d6 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,15 +1,7 @@
 GIT
-  remote: https://github.com/CodiTramuntana/decidim-module-term_customizer
-  revision: c4ed0ffa87bd9977c6b470aa815d5dc2ed9f88a5
-  specs:
-    decidim-term_customizer (0.18.0)
-      decidim-admin (>= 0.18.0)
-      decidim-core (>= 0.18.0)
-
-GIT
-  remote: https://github.com/decidim/decidim
-  revision: 2f1e3c8ad256dfc2616530a5049107e6335eceea
-  branch: release/0.24-stable
+  remote: https://github.com/AjuntamentdeBarcelona/decidim
+  revision: e471864fcb4011b096ed31ea312814d6299b9f3d
+  branch: feature/bcn-budget-v0.24
   specs:
     decidim (0.24.2)
       decidim-accountability (= 0.24.2)
@@ -225,12 +217,32 @@ GIT
     decidim-verifications (0.24.2)
       decidim-core (= 0.24.2)
 
+GIT
+  remote: https://github.com/CodiTramuntana/decidim-module-term_customizer
+  revision: c4ed0ffa87bd9977c6b470aa815d5dc2ed9f88a5
+  specs:
+    decidim-term_customizer (0.18.0)
+      decidim-admin (>= 0.18.0)
+      decidim-core (>= 0.18.0)
+
+PATH
+  remote: decidim-census_sms
+  specs:
+    decidim-census_sms (0.0.1)
+      decidim-core
+
 PATH
   remote: decidim-dataviz
   specs:
     decidim-dataviz (0.0.1)
       decidim-core
 
+PATH
+  remote: decidim-ephemeral_participation
+  specs:
+    decidim-ephemeral_participation (0.0.1)
+      decidim-verifications
+
 PATH
   remote: decidim-stats
   specs:
@@ -352,7 +364,7 @@ GEM
       actionpack (>= 3.0)
       cells (>= 4.1.6, < 5.0.0)
     charlock_holmes (0.7.7)
-    chef-utils (17.0.242)
+    chef-utils (17.1.35)
       concurrent-ruby
     childprocess (3.0.0)
     coercible (1.0.0)
@@ -410,7 +422,7 @@ GEM
     doc2text (0.4.3)
       nokogiri (~> 1.11.1)
       rubyzip (~> 2.3.0)
-    docile (1.3.5)
+    docile (1.4.0)
     domain_name (0.5.20190701)
       unf (>= 0.0.5, < 1.0.0)
     doorkeeper (5.5.1)
@@ -503,7 +515,7 @@ GEM
     graphiql-rails (1.4.11)
       railties
       sprockets-rails
-    graphql (1.12.9)
+    graphql (1.12.10)
     hashdiff (1.0.1)
     hashie (4.1.0)
     highline (2.0.3)
@@ -653,7 +665,7 @@ GEM
       activerecord (>= 5.2)
       activesupport (>= 5.2)
     polyglot (0.3.5)
-    premailer (1.14.3)
+    premailer (1.15.0)
       addressable
       css_parser (>= 1.6.0)
       htmlentities (>= 4.0.0)
@@ -839,7 +851,7 @@ GEM
     smart_properties (1.15.0)
     social-share-button (1.2.4)
       coffee-rails
-    spreadsheet (1.2.8)
+    spreadsheet (1.2.9)
       ruby-ole
     spring (2.1.1)
     spring-watcher-listen (2.0.1)
@@ -891,7 +903,7 @@ GEM
       virtus (~> 1.0)
     warden (1.2.9)
       rack (>= 2.0.9)
-    webmock (3.12.2)
+    webmock (3.13.0)
       addressable (>= 2.3.6)
       crack (>= 0.3.2)
       hashdiff (>= 0.4.0, < 2.0.0)
@@ -917,8 +929,10 @@ DEPENDENCIES
   dalli
   database_cleaner
   decidim!
+  decidim-census_sms!
   decidim-dataviz!
   decidim-dev!
+  decidim-ephemeral_participation!
   decidim-initiatives!
   decidim-navigation_maps (~> 1.2.0)
   decidim-sortitions!
diff --git a/app/assets/stylesheets/_barcelona.scss b/app/assets/stylesheets/_barcelona.scss
index 831cb7d6be..5ab323f409 100644
--- a/app/assets/stylesheets/_barcelona.scss
+++ b/app/assets/stylesheets/_barcelona.scss
@@ -7,3 +7,4 @@
 @import "theme-barcelona/hero-custom";
 @import "theme-barcelona/event-days";
 @import "theme-barcelona/special-process";
+@import "theme-barcelona/budgets";
diff --git a/app/assets/stylesheets/theme-barcelona/_budgets.scss b/app/assets/stylesheets/theme-barcelona/_budgets.scss
new file mode 100644
index 0000000000..25b8f8c9c2
--- /dev/null
+++ b/app/assets/stylesheets/theme-barcelona/_budgets.scss
@@ -0,0 +1,11 @@
+.budget-progress {
+  .progress-meter {
+    &:not(&--minimum) {
+      background-color: $red-light;
+    }
+  }
+}
+
+#project .card.extra .button_to {
+  display: none;
+}
diff --git a/app/services/census_authorization_handler.rb b/app/services/census_authorization_handler.rb
index f71c0b5344..c8e938c9c6 100644
--- a/app/services/census_authorization_handler.rb
+++ b/app/services/census_authorization_handler.rb
@@ -56,7 +56,7 @@ def census_document_types
 
   def unique_id
     Digest::MD5.hexdigest(
-      "#{document_number&.upcase}-#{Rails.application.secrets.secret_key_base}"
+      "#{sanitized_document_number}-#{Rails.application.secrets.secret_key_base}"
     )
   end
 
@@ -83,6 +83,10 @@ def document_type_valid
     errors.add(:document_number, I18n.t("census_authorization_handler.invalid_document")) unless response.xpath("//codiRetorn").text == "01"
   end
 
+  def sanitized_document_number
+    document_number&.gsub(/[^A-Za-z0-9]/, "")&.upcase
+  end
+
   def response
     return nil if document_number.blank? ||
                   document_type.blank? ||
@@ -109,7 +113,7 @@ def request_body
       <sch:usuari>PAM</sch:usuari>
       <sch:Dades>
         <sch:tipDocument>#{sanitized_document_type}</sch:tipDocument>
-        <sch:docId>#{sanitize document_number&.upcase}</sch:docId>
+        <sch:docId>#{sanitized_document_number}</sch:docId>
         <sch:codiPostal>#{sanitize postal_code}</sch:codiPostal>
         <sch:dataNaixConst>#{sanitized_date_of_birth}</sch:dataNaixConst>
       </sch:Dades>
diff --git a/config/initializers/decidim.rb b/config/initializers/decidim.rb
index 5e2613c017..c3730ec0df 100644
--- a/config/initializers/decidim.rb
+++ b/config/initializers/decidim.rb
@@ -23,6 +23,22 @@
 
   if Rails.application.secrets.sms.values.all?(&:present?)
     config.sms_gateway_service = "SmsGateway"
+
+    Decidim::Verifications.register_workflow(:census_sms_authorization_handler) do |auth|
+      auth.engine = Decidim::CensusSms::Verification::Engine
+      auth.action_authorizer = "Decidim::CensusSms::Verification::ActionAuthorizer"
+      auth.renewable = true
+      auth.time_between_renewals = 1.day
+      auth.ephemerable = true
+
+      auth.options do |options|
+        parent_scope = Decidim::Scope.where("name->>'ca' = 'Ciutat'").first
+
+        Decidim::Scope.where(parent: parent_scope).pluck(:code).each do |code|
+          options.attribute :"scope_code_#{code}", type: :boolean, required: false
+        end
+      end
+    end
   end
 
   config.timestamp_service = "TimestampService"
@@ -38,6 +54,7 @@
   auth.renewable = true
   auth.time_between_renewals = 1.day
   auth.metadata_cell = "census_authorization_metadata"
+  auth.ephemerable = true
 end
 
 Decidim::Verifications.register_workflow(:census16_authorization_handler) do |auth|
@@ -45,4 +62,5 @@
   auth.renewable = true
   auth.time_between_renewals = 1.day
   auth.metadata_cell = "census16_authorization_metadata"
+  auth.ephemerable = true
 end
diff --git a/config/initializers/decidim_budgets.rb b/config/initializers/decidim_budgets.rb
index f01984a31d..f2afcdfdda 100644
--- a/config/initializers/decidim_budgets.rb
+++ b/config/initializers/decidim_budgets.rb
@@ -1,4 +1,6 @@
 # frozen_string_literal: true
 
 require "budgets_workflow_pam2020"
+require "budgets_workflow_pam2021"
 Decidim::Budgets.workflows[:pam2020] = BudgetsWorkflowPam2020
+Decidim::Budgets.workflows[:pam2021] = BudgetsWorkflowPam2021
diff --git a/config/locales/ca.yml b/config/locales/ca.yml
index f661cfd228..eac57d8ed9 100644
--- a/config/locales/ca.yml
+++ b/config/locales/ca.yml
@@ -141,6 +141,9 @@ ca:
         first_login:
           actions:
             census_authorization_handler: Verifica't amb el padró
+            census16_authorization_handler: Verifica't amb el padró (16+)
+            census_sms_authorization_handler: Verifica't amb el padró i el teu mòbil
+            valid_auth: Valid auth
     initiatives:
       initiatives:
         supports:
@@ -154,4 +157,4 @@ ca:
     home:
       extended:
         debates_explanation: Espais per informar-te i decidir sobre les propostes
-          de cada procés.
+          de cada procés.
\ No newline at end of file
diff --git a/config/locales/decidim_budgets_workflows_ca.yml b/config/locales/decidim_budgets_workflows_ca.yml
new file mode 100644
index 0000000000..45ef09a819
--- /dev/null
+++ b/config/locales/decidim_budgets_workflows_ca.yml
@@ -0,0 +1,11 @@
+ca:
+  decidim:
+    components:
+      budgets:
+        settings:
+          global:
+            ephemerous_census_data_verification: Ephemerous Census Data Verification
+            workflow_choices:
+              pam2020: "PAM 2020: allows to Vote in the participant's district and in another of free choice."
+              pam2021: "PAM 2021: allows to Vote in the participant's district and in another of free choice."
+
diff --git a/config/locales/decidim_budgets_workflows_en.yml b/config/locales/decidim_budgets_workflows_en.yml
index 465fa2bdf7..5d18909d7d 100644
--- a/config/locales/decidim_budgets_workflows_en.yml
+++ b/config/locales/decidim_budgets_workflows_en.yml
@@ -4,5 +4,7 @@ en:
       budgets:
         settings:
           global:
+            ephemerous_census_data_verification: Ephemerous Census Data Verification
             workflow_choices:
               pam2020: "PAM 2020: allows to Vote in the participant's district and in another of free choice."
+              pam2021: "PAM 2021: allows to Vote in the participant's district and in another of free choice."
diff --git a/config/locales/decidim_budgets_workflows_es.yml b/config/locales/decidim_budgets_workflows_es.yml
new file mode 100644
index 0000000000..349f22458f
--- /dev/null
+++ b/config/locales/decidim_budgets_workflows_es.yml
@@ -0,0 +1,11 @@
+es:
+  decidim:
+    components:
+      budgets:
+        settings:
+          global:
+            ephemerous_census_data_verification: Ephemerous Census Data Verification
+            workflow_choices:
+              pam2020: "PAM 2020: allows to Vote in the participant's district and in another of free choice."
+              pam2021: "PAM 2021: allows to Vote in the participant's district and in another of free choice."
+
diff --git a/config/routes.rb b/config/routes.rb
index 0cc29c5da3..6d31ba014f 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -55,4 +55,6 @@
   mount Decidim::Core::Engine => "/"
   # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
   mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?
+
+  mount Decidim::EphemeralParticipation::Engine, at: "/", as: "decidim_ephemeral_participation"
 end
diff --git a/config/secrets.yml b/config/secrets.yml
index b878e0c20f..3334e4e6b0 100644
--- a/config/secrets.yml
+++ b/config/secrets.yml
@@ -60,6 +60,13 @@ test:
   secret_key_base: 4a6fd36ca5634dbf42f63331b1a236a041976561ec314414d1750f33ef691dd3705ff2828a607d98bee0ba492e11281a33e736c71e959ab04c76679e74ecb564
   geocoder:
     here_api_key: 1234123412341234
+  sms:
+    service_url: http://example.org/sms
+    proxy_url: http://example.org/proxy
+    username: username
+    password: password
+    service_id: "1234"
+    sub_service_id: "1234"
 
 # Do not keep production secrets in the repository,
 # instead read values from the environment.
diff --git a/db/migrate/20210518204806_update_organizations_available_authorizations.decidim_ephemeral_participation.rb b/db/migrate/20210518204806_update_organizations_available_authorizations.decidim_ephemeral_participation.rb
new file mode 100644
index 0000000000..3b0434893c
--- /dev/null
+++ b/db/migrate/20210518204806_update_organizations_available_authorizations.decidim_ephemeral_participation.rb
@@ -0,0 +1,41 @@
+# This migration comes from decidim_ephemeral_participation (originally 20210518192857)
+class UpdateOrganizationsAvailableAuthorizations < ActiveRecord::Migration[5.2]
+  class Organization < ApplicationRecord
+    self.table_name = :decidim_organizations
+  end
+
+  def up
+    workflows = {}
+
+    Organization.find_each do |organization|
+      workflows[organization.id] =
+        organization.available_authorizations.to_a.each_with_object({}) do |workflow, hash|
+          hash[workflow] = { allow_ephemeral_participation: false }
+        end
+    end
+    
+    remove_column :decidim_organizations, :available_authorizations
+    add_column    :decidim_organizations, :available_authorizations, :jsonb, default: {}
+    Organization.reset_column_information
+    
+    Organization.find_each do |organization|
+      organization.update!(available_authorizations: workflows[organization.id])
+    end
+  end
+
+  def down
+    workflows = {}
+    
+    Organization.find_each do |organization|
+      workflows[organization.id] = organization.available_authorizations.keys.presence
+    end
+
+    remove_column :decidim_organizations, :available_authorizations
+    add_column    :decidim_organizations, :available_authorizations, :string, array: true, default: []
+    Organization.reset_column_information
+
+    Organization.find_each do |organization|
+      organization.update!(available_authorizations: workflows[organization.id])
+    end
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 851b95f9b1..55883734b6 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 2021_04_22_132738) do
+ActiveRecord::Schema.define(version: 2021_05_18_204806) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "ltree"
@@ -973,7 +973,6 @@
     t.string "github_handler"
     t.string "reference_prefix", null: false
     t.string "secondary_hosts", default: [], array: true
-    t.string "available_authorizations", default: [], array: true
     t.text "header_snippets"
     t.jsonb "cta_button_text"
     t.string "cta_button_path"
@@ -1008,6 +1007,7 @@
     t.integer "comments_max_length", default: 1000
     t.jsonb "file_upload_settings"
     t.string "machine_translation_display_priority", default: "original", null: false
+    t.jsonb "available_authorizations", default: {}
     t.index ["host"], name: "index_decidim_organizations_on_host", unique: true
     t.index ["name"], name: "index_decidim_organizations_on_name", unique: true
   end
diff --git a/decidim-census_sms/README.md b/decidim-census_sms/README.md
new file mode 100644
index 0000000000..9fe18965e1
--- /dev/null
+++ b/decidim-census_sms/README.md
@@ -0,0 +1,13 @@
+# Decidim::CensusSms::Verification
+The CensusSms module adds a verification workflow that checks users against the Census database and sends a code to their mobile phone number to confirm their identity. 
+
+## Usage
+Activate workflow in the system panel.
+
+## Contributing
+See [Decidim
+Barcelona](https://github.com/AjuntamentdeBarcelona/decidim-barcelona).
+
+## License
+See [Decidim
+Barcelona](https://github.com/AjuntamentdeBarcelona/decidim-barcelona).
diff --git a/decidim-census_sms/Rakefile b/decidim-census_sms/Rakefile
new file mode 100644
index 0000000000..447b5c1bf2
--- /dev/null
+++ b/decidim-census_sms/Rakefile
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+require "decidim/dev/common_rake"
diff --git a/decidim-census_sms/app/assets/config/decidim_census_sms_manifest.css b/decidim-census_sms/app/assets/config/decidim_census_sms_manifest.css
new file mode 100644
index 0000000000..830b3d1983
--- /dev/null
+++ b/decidim-census_sms/app/assets/config/decidim_census_sms_manifest.css
@@ -0,0 +1,3 @@
+/*
+ *= link decidim/census_sms/verification.scss
+ */
diff --git a/decidim-census_sms/app/assets/stylesheets/decidim/census_sms/verification.scss b/decidim-census_sms/app/assets/stylesheets/decidim/census_sms/verification.scss
new file mode 100644
index 0000000000..4463b25a22
--- /dev/null
+++ b/decidim-census_sms/app/assets/stylesheets/decidim/census_sms/verification.scss
@@ -0,0 +1,24 @@
+.new_authorization {
+  .field.date {
+    label {
+      display: grid;
+      grid-template-columns: repeat(3, 1fr);
+      gap: 5px;
+    }
+
+    select {
+      grid-row: 2;
+    }
+
+    .label-required {
+      width: 0.5rem;
+      grid-column: 3;
+      justify-self: flex-end;
+    }
+
+    .form-error {
+      grid-row: 3;
+      grid-column: span 3;
+    }
+  }
+}
diff --git a/decidim-census_sms/app/commands/decidim/census_sms/verification/reset_code.rb b/decidim-census_sms/app/commands/decidim/census_sms/verification/reset_code.rb
new file mode 100644
index 0000000000..d6fdd3e414
--- /dev/null
+++ b/decidim-census_sms/app/commands/decidim/census_sms/verification/reset_code.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+module Decidim
+  module CensusSms
+    module Verification
+      class ResetCode < Rectify::Command
+        # Public: Initializes the command.
+        #
+        # form          - A form object with the params.
+        # authorization - The authorization object to update.
+        def initialize(form, authorization)
+          @form = form
+          @authorization = authorization
+        end
+
+        # Executes the command
+        # Broadcasts these events:
+        #
+        # - :ok when everything is valid.
+        # - :invalid if the handler wasn't valid and we couldn't proceed.
+        #
+        # Returns nothing.
+        def call
+          return broadcast(:ok) if update_authorization
+
+          broadcast(:invalid)
+        end
+
+        private
+
+        def update_authorization
+          metadata = @authorization.metadata
+          metadata[:mobile_phone_number] = @form.mobile_phone_number_hash
+
+          @authorization.update(metadata: metadata, verification_metadata: verification_metadata)
+        end
+
+        def verification_metadata
+          {
+            verification_code: @form.generated_code,
+            code_sent_at: Time.current
+          }
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-census_sms/app/controllers/decidim/census_sms/verification/authorizations_controller.rb b/decidim-census_sms/app/controllers/decidim/census_sms/verification/authorizations_controller.rb
new file mode 100644
index 0000000000..ee1b41aa09
--- /dev/null
+++ b/decidim-census_sms/app/controllers/decidim/census_sms/verification/authorizations_controller.rb
@@ -0,0 +1,115 @@
+# frozen_string_literal: true
+
+module Decidim
+  module CensusSms
+    module Verification
+      class AuthorizationsController < Decidim::ApplicationController
+        include Decidim::Verifications::Renewable
+
+        helper_method :authorization, :tos_path
+
+        def new
+          enforce_permission_to :create, :authorization, authorization: authorization
+
+          @form = AuthorizationForm.new
+        end
+
+        def create
+          enforce_permission_to :create, :authorization, authorization: authorization
+
+          @form = AuthorizationForm.from_params(create_params)
+
+          Decidim::Verifications::PerformAuthorizationStep.call(authorization, @form) do
+            on(:ok) do
+              flash[:notice] = t("authorizations.create.success", scope: "decidim.census_sms.verification")
+              authorization_method = Decidim::Verifications::Adapter.from_element(authorization.name)
+              redirect_to authorization_method.resume_authorization_path(redirect_url: redirect_url)
+            end
+
+            on(:invalid) do
+              flash.now[:alert] = t("authorizations.create.error", scope: "decidim.census_sms.verification")
+              render :new
+            end
+          end
+        end
+
+        def edit
+          enforce_permission_to :update, :authorization, authorization: authorization
+
+          @form = Decidim::Verifications::Sms::ConfirmationForm.from_params(params)
+        end
+
+        def update
+          enforce_permission_to :update, :authorization, authorization: authorization
+
+          @form = Decidim::Verifications::Sms::ConfirmationForm.from_params(params)
+
+          Decidim::Verifications::ConfirmUserAuthorization.call(authorization, @form, session) do
+            on(:ok) do
+              flash[:notice] = t("authorizations.update.success", scope: "decidim.census_sms.verification")
+              redirect_to decidim_verifications.authorizations_path
+            end
+
+            on(:invalid) do
+              flash.now[:alert] = t("authorizations.update.error", scope: "decidim.census_sms.verification")
+              render :edit
+            end
+          end
+        end
+
+        def reset
+          enforce_permission_to :update, :authorization, authorization: authorization
+
+          @form = ResetForm.from_params(params)
+
+          return unless request.post?
+
+          ResetCode.call(@form, authorization) do
+            on(:ok) do
+              flash[:notice] = t("authorizations.reset.success", scope: "decidim.census_sms.verification")
+              authorization_method = Decidim::Verifications::Adapter.from_element(authorization.name)
+              redirect_to authorization_method.resume_authorization_path(redirect_url: redirect_url)
+            end
+
+            on(:invalid) do
+              flash.now[:alert] = t("authorizations.reset.error", scope: "decidim.census_sms.verification")
+              render :reset
+            end
+          end
+        end
+
+        def destroy
+          enforce_permission_to :destroy, :authorization, authorization: authorization
+
+          authorization.destroy!
+          flash[:notice] = t("authorizations.destroy.success", scope: "decidim.census_sms.verification")
+
+          redirect_to action: :new
+        end
+
+        private
+
+        def create_params
+          params[:authorization].merge(user: current_user, date_of_birth: date_of_birth)
+        end
+
+        def date_of_birth
+          year, month, day = params[:authorization].select { |k, _v| k.include?("date_of_birth") }.values.reverse.map(&:to_i)
+
+          Date.new(year, month, day)
+        end
+
+        def authorization
+          @authorization ||= Decidim::Authorization.find_or_initialize_by(
+            user: current_user,
+            name: "census_sms_authorization_handler"
+          )
+        end
+
+        def tos_path
+          @terms_and_conditions_page_path ||= decidim.page_path(Decidim::StaticPage.find_by(slug: "terms-and-conditions", organization: current_organization))
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-census_sms/app/forms/decidim/census_sms/verification/authorization_form.rb b/decidim-census_sms/app/forms/decidim/census_sms/verification/authorization_form.rb
new file mode 100644
index 0000000000..dfc0d4ba43
--- /dev/null
+++ b/decidim-census_sms/app/forms/decidim/census_sms/verification/authorization_form.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+# Checks the authorization against the census for Barcelona.
+require "digest/md5"
+
+# This class performs a check against the official census database in order
+# to verify the citizen's residence and sends an SMS to confirm identity.
+module Decidim
+  module CensusSms
+    module Verification
+      class AuthorizationForm < CensusAuthorizationHandler
+        attribute :mobile_phone_number, String
+        attribute :tos_acceptance, Boolean
+
+        validates :mobile_phone_number, :verification_code, :sms_gateway, presence: true
+        validates :tos_acceptance, acceptance: true
+
+        # If you need to store any of the defined attributes in the authorization you
+        # can do it here.
+        #
+        # You must return a Hash that will be serialized to the authorization when
+        # it's created, and available though authorization.metadata
+        def metadata
+          super.merge(
+            tos_accepted_at: Time.now,
+            mobile_phone_number: mobile_phone_number_hash,
+            scope_code: scope.code
+          )
+        end
+
+        # The verification metadata to validate in the next step.
+        def verification_metadata
+          {
+            verification_code: verification_code,
+            code_sent_at: Time.current
+          }
+       end
+
+        # When there's a phone number, sanitize it allowing only numbers and +.
+        def mobile_phone_number
+          return unless super
+
+          super.gsub(/[^+0-9]/, "")
+        end
+
+        private
+
+        def sms_gateway
+          Decidim.sms_gateway_service.to_s.safe_constantize
+        end
+
+        def verification_code
+          return unless sms_gateway
+          return @verification_code if defined?(@verification_code)
+
+          # DEBUG #TODO UNCOMMENT
+          # return unless sms_gateway.new(mobile_phone_number, generated_code).deliver_code
+
+          @verification_code = generated_code
+        end
+
+        def generated_code
+          @generated_code ||= SecureRandom.random_number(1_000_000).to_s
+        end
+
+        # A mobile phone can only be verified once but it should be private.
+        def mobile_phone_number_hash
+          Digest::MD5.hexdigest(
+            "#{mobile_phone_number}-#{Rails.application.secrets.secret_key_base}"
+          )
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-census_sms/app/forms/decidim/census_sms/verification/reset_form.rb b/decidim-census_sms/app/forms/decidim/census_sms/verification/reset_form.rb
new file mode 100644
index 0000000000..24bd45e40a
--- /dev/null
+++ b/decidim-census_sms/app/forms/decidim/census_sms/verification/reset_form.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+module Decidim
+  module CensusSms
+    module Verification
+      # A form object to reset verification code and send it again.
+      class ResetForm < Form
+        attribute :mobile_phone_number, String
+
+        validates :mobile_phone_number, :verification_code, :sms_gateway, presence: true
+
+        # When there's a phone number, sanitize it allowing only numbers and +.
+        def mobile_phone_number
+          return unless super
+
+          super.gsub(/[^+0-9]/, "")
+        end
+
+        # A mobile phone can only be verified once but it should be private.
+        def mobile_phone_number_hash
+          Digest::MD5.hexdigest(
+            "#{mobile_phone_number}-#{Rails.application.secrets.secret_key_base}"
+          )
+        end
+
+        def generated_code
+          @generated_code ||= SecureRandom.random_number(1_000_000).to_s
+        end
+
+        private
+
+        def verification_code
+          return unless sms_gateway
+          return @verification_code if defined?(@verification_code)
+
+          return unless sms_gateway.new(mobile_phone_number, generated_code).deliver_code
+
+          @verification_code = generated_code
+        end
+
+        def sms_gateway
+          Decidim.sms_gateway_service.to_s.safe_constantize
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-census_sms/app/services/decidim/census_sms/verification/action_authorizer.rb b/decidim-census_sms/app/services/decidim/census_sms/verification/action_authorizer.rb
new file mode 100644
index 0000000000..8859a1b0aa
--- /dev/null
+++ b/decidim-census_sms/app/services/decidim/census_sms/verification/action_authorizer.rb
@@ -0,0 +1,35 @@
+module Decidim
+  module CensusSms
+    module Verification
+      class ActionAuthorizer < Decidim::Verifications::DefaultActionAuthorizer
+        BASE_OPTION_KEY = "scope_code".freeze
+
+        protected
+
+        def missing_fields
+          authorized_code.present? ? [] : [BASE_OPTION_KEY]
+        end
+
+        def unmatched_fields
+          scope_valid? ? [] : [BASE_OPTION_KEY]
+        end
+
+        private
+
+        def scope_valid?
+          scope_codes = options.keys.map { |k| k.gsub("#{BASE_OPTION_KEY}_", "") if k.match?(BASE_OPTION_KEY) }.compact
+
+          return unless scope_codes.any?
+
+          authorized_code_key = "#{BASE_OPTION_KEY}_#{authorized_code}"
+
+          authorized_code.present? && options[authorized_code_key] == "1"
+        end
+
+        def authorized_code
+          authorization.metadata[BASE_OPTION_KEY]
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-census_sms/app/views/decidim/census_sms/verification/authorizations/edit.html.erb b/decidim-census_sms/app/views/decidim/census_sms/verification/authorizations/edit.html.erb
new file mode 100644
index 0000000000..5fd88782fa
--- /dev/null
+++ b/decidim-census_sms/app/views/decidim/census_sms/verification/authorizations/edit.html.erb
@@ -0,0 +1,29 @@
+<div class="wrapper">
+  <div class="row">
+    <div class="columns large-6 large-centered">
+      <h1 class="text-center page-title"><%= t(".title") %></h1>
+    </div>
+    
+    <div class="card columns large-6 large-centered">
+      <div class="card__content">
+        <%= decidim_form_for(@form, url: authorization_path(redirect_url: redirect_url), method: :put) do |form| %>
+          <%= form_required_explanation %>
+
+          <div class="field">
+            <%= form.text_field :verification_code %>
+          </div>
+
+          <div class="actions">
+            <%= form.submit t(".send"), class: "button expanded", "data-disable-with" => "#{t('.send')}..." %>
+          </div>
+        <% end %>
+      </div>
+    </div>
+    <div class="card columns large-6 large-centered">
+      <div class="card__content">
+        <%= t(".instructions") %>
+        <%= link_to t(".reset"), reset_authorization_path(id: authorization.id) %>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/decidim-census_sms/app/views/decidim/census_sms/verification/authorizations/new.html.erb b/decidim-census_sms/app/views/decidim/census_sms/verification/authorizations/new.html.erb
new file mode 100644
index 0000000000..9ad8b079c7
--- /dev/null
+++ b/decidim-census_sms/app/views/decidim/census_sms/verification/authorizations/new.html.erb
@@ -0,0 +1,58 @@
+<div class="wrapper">
+  <div class="row">
+    <div class="columns large-6 large-centered">
+      <h1 class="text-center page-title"><%= t(".title") %></h1>
+    </div>
+    
+    <div class="card columns large-6 large-centered">
+      <div class="card__content">
+        <%= decidim_form_for(@form, url: authorization_path) do |form| %>
+          <%= form_required_explanation %>
+
+          <div class="field">
+            <%= form.select :document_type, form.object.census_document_types, prompt: true %>
+          </div>
+
+          <div class="field">
+            <%= form.text_field :document_number %>
+          </div>
+
+          <div class="field date">
+            <%= form.date_select :date_of_birth, start_year: 1900, end_year: 14.years.ago.year, default: 35.years.ago, prompt: { day: t(".date_select.day"), month: t(".date_select.month"), year: t(".date_select.year") } %>
+          </div>
+
+          <div class="field">
+            <%= form.text_field :postal_code %>
+            <p class="help-text">
+              <%== t(".postal_code_help") %>
+            </p>
+          </div>
+
+          <div class="field">
+            <% parent_scope = Decidim::Scope.where("name->>'ca' = 'Ciutat'").first %>
+            <%= form.collection_select :scope_id, current_organization.scopes.where(parent: parent_scope), :id, ->(scope){ translated_attribute(scope.name) }, prompt: t(".scope_prompt") %>
+          </div>
+
+          <div class="field">
+            <%= form.phone_field :mobile_phone_number %>
+          </div>
+
+          <div class="field">
+            <%= form.label :tos_acceptance do %>
+              <%= form.check_box :tos_acceptance, label: false %>
+              <%== t("activemodel.attributes.authorization.tos_acceptance_label", tos_path: tos_path) %>
+            <% end %>
+          </div>
+
+          <%= form.hidden_field :handler_name %>
+
+          <div class="actions mt-s">
+            <%= form.submit t(".send"), class: "button expanded", "data-disable-with" => "#{t('.send')}..." %>
+          </div>
+        <% end %>
+      </div>
+    </div>
+  </div>
+</div>
+
+<%= stylesheet_link_tag "decidim/census_sms/verification" %>
diff --git a/decidim-census_sms/app/views/decidim/census_sms/verification/authorizations/reset.html.erb b/decidim-census_sms/app/views/decidim/census_sms/verification/authorizations/reset.html.erb
new file mode 100644
index 0000000000..c638e99df5
--- /dev/null
+++ b/decidim-census_sms/app/views/decidim/census_sms/verification/authorizations/reset.html.erb
@@ -0,0 +1,23 @@
+<div class="wrapper">
+  <div class="row">
+    <div class="columns large-6 large-centered">
+      <h1 class="text-center page-title"><%= t(".title") %></h1>
+    </div>
+    
+    <div class="card columns large-6 large-centered">
+      <div class="card__content">
+        <%= decidim_form_for(@form, url: reset_authorization_path(id: authorization.id), method: :post) do |form| %>
+          <%= form_required_explanation %>
+
+          <div class="field">
+            <%= form.text_field :mobile_phone_number, label: t("mobile_phone_number", scope: "activemodel.attributes.authorization") %>
+          </div>
+
+          <div class="actions">
+            <%= form.submit t(".send"), class: "button expanded", "data-disable-with" => "#{t('.send')}..." %>
+          </div>
+        <% end %>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/decidim-census_sms/config/i18n-tasks.yml b/decidim-census_sms/config/i18n-tasks.yml
new file mode 100644
index 0000000000..7c55c3e957
--- /dev/null
+++ b/decidim-census_sms/config/i18n-tasks.yml
@@ -0,0 +1,2 @@
+base_locale: ca
+locales: [ca,es]
\ No newline at end of file
diff --git a/decidim-census_sms/config/locales/ca.yml b/decidim-census_sms/config/locales/ca.yml
new file mode 100644
index 0000000000..a4cc568cc2
--- /dev/null
+++ b/decidim-census_sms/config/locales/ca.yml
@@ -0,0 +1,58 @@
+---
+ca:
+  activemodel:
+    attributes:
+      authorization:
+        date_of_birth: Data de naixement
+        document_number: Número de document
+        document_type: Tipus de document
+        mobile_phone_number: Número de telèfon mòbil
+        postal_code: Codi postal
+        scope_id: Districte
+        tos_acceptance: Accepto els Termes i Condicions
+        tos_acceptance_label: En registrar-te acceptes els <a class="link" href="%{tos_path}" target="_blank">Termes i Condicions</a>
+  decidim:
+    authorization_handlers:
+      census_sms_authorization_handler:
+        explanation: El padró + SMS #TODO
+        name: El padró + SMS #TODO
+        fields:
+          scope_code_1: Districte 1 #TODO
+          scope_code_2: Districte 2 #TODO
+          scope_code_3: Districte 3 #TODO
+          scope_code_4: Districte 4 #TODO
+          scope_code_5: Districte 5 #TODO
+          scope_code_6: Districte 6 #TODO
+          scope_code_7: Districte 7 #TODO
+          scope_code_8: Districte 8 #TODO
+          scope_code_9: Districte 9 #TODO
+          scope_code_10: Districte 10 #TODO
+          scope_code: Districte
+    census_sms:
+      verification:
+        authorizations:
+          create:
+            error: S'ha produit un error en crear l'autorització
+            success: Has completat el primer pas per obtenir l'autorització
+          edit:
+            instructions: No has rebut el codi de verificació? 
+            reset: Restableix el codi de verificació
+            send: Verifica't
+            title: Introdueix el codi que has rebut per SMS
+          new:
+            date_select:
+              day: Dia
+              month: Mes
+              year: Any
+            postal_code_help: No saps quin codi postal correspon a la teva adreça del Padró? Pots consultar-ho <a target="_blank" href="https://www.correos.es/es/ca/eines/codis-postals/detall">clicant aquí</a>.
+            scope_prompt: Selecciona el teu districte
+            send: Verifica't
+            title: Verifica't amb el Padró
+          reset:
+            mobile_phone_number: Número de telèfon mòbil
+            send: Envia'm un nou codi
+            title: Restableix el codi de verificació
+            success: T'hem enviat un nou codi de verificació
+          update:
+            error: El codi de verificació que has introduït no coincideix amb el nostre. Si us plau, revisa l'SMS que t'hem enviat.
+            success: Felicitats. T'has verificat correctament.
diff --git a/decidim-census_sms/config/locales/es.yml b/decidim-census_sms/config/locales/es.yml
new file mode 100644
index 0000000000..5f56cbc36f
--- /dev/null
+++ b/decidim-census_sms/config/locales/es.yml
@@ -0,0 +1,5 @@
+---
+es:
+  decidim:
+    census_sms:
+      verification:
\ No newline at end of file
diff --git a/decidim-census_sms/decidim-census_sms.gemspec b/decidim-census_sms/decidim-census_sms.gemspec
new file mode 100644
index 0000000000..b1a7202833
--- /dev/null
+++ b/decidim-census_sms/decidim-census_sms.gemspec
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+$LOAD_PATH.push File.expand_path("lib", __dir__)
+
+Gem::Specification.new do |s|
+  s.name        = "decidim-census_sms"
+  s.summary     = "A verification workflow for Decidim Barcelona."
+  s.description = s.summary
+  s.version     = "0.0.1"
+  s.authors     = ["Vera Rojman"]
+  s.email       = ["vera@platoniq.net"]
+
+  s.files = Dir["{app,config,lib}/**/*", "Rakefile", "README.md"]
+
+  s.add_dependency "decidim-core"
+
+  s.add_development_dependency "decidim-dev"
+end
diff --git a/decidim-census_sms/lib/decidim/census_sms.rb b/decidim-census_sms/lib/decidim/census_sms.rb
new file mode 100644
index 0000000000..9710f1a689
--- /dev/null
+++ b/decidim-census_sms/lib/decidim/census_sms.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require "decidim/census_sms/verification"
+
+module Decidim
+  # Base module for this engine.
+  module CensusSms
+  end
+end
diff --git a/decidim-census_sms/lib/decidim/census_sms/verification.rb b/decidim-census_sms/lib/decidim/census_sms/verification.rb
new file mode 100644
index 0000000000..4f2f5b3949
--- /dev/null
+++ b/decidim-census_sms/lib/decidim/census_sms/verification.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+require "decidim/census_sms/verification/engine"
+
+module Decidim
+  module CensusSms
+    module Verification
+    end
+  end
+end
diff --git a/decidim-census_sms/lib/decidim/census_sms/verification/engine.rb b/decidim-census_sms/lib/decidim/census_sms/verification/engine.rb
new file mode 100644
index 0000000000..27e137ba4f
--- /dev/null
+++ b/decidim-census_sms/lib/decidim/census_sms/verification/engine.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Decidim
+  module CensusSms
+    module Verification
+      # This is an engine that performs user authorization.
+      class Engine < ::Rails::Engine
+        isolate_namespace Decidim::CensusSms::Verification
+
+        paths["db/migrate"] = nil
+        paths["lib/tasks"] = nil
+
+        routes do
+          resource :authorizations, only: [:new, :create, :edit, :update, :destroy], as: :authorization do
+            get :reset, on: :member
+            post :reset, on: :member
+            get :renew, on: :collection
+          end
+          root to: "authorizations#new"
+        end
+
+        initializer "decidim_census_sms.assets" do |app|
+          app.config.assets.precompile += %w(decidim_census_sms_manifest.css
+                                             decidim/census_sms/verification.scss)
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/README.md b/decidim-ephemeral_participation/README.md
new file mode 100644
index 0000000000..785ab21109
--- /dev/null
+++ b/decidim-ephemeral_participation/README.md
@@ -0,0 +1,44 @@
+# Decidim::EphemeralParticipation
+
+This module adds a specific integration with local Barcelona services so citizens can participate without registration.
+
+> NOTE: this module might be provisional if the main changes introduces by it are ported to `decidim-core`
+> (which is the intention of the team behind it)
+
+## Install
+
+Available_authorizations can now hold some configurable data, this migrations takes car of updating the organization field:
+
+```
+rails decidim_ephemeral_participation:install:migrations
+```
+
+In order to allow an Authorization handler to be used for ephemeral participation, it needs to be configured in the initializer:
+
+```ruby
+# config/initializers/decidim.rb
+
+Decidim::Verifications.register_workflow(:census) do |workflow|
+  workflow.form = "myAuthorizationHandlerClass"
+  workflow.renewable = true
+  workflow.time_between_renewals = 1.day
+  workflow.metadata_cell = "decidim/verifications/authorization_metadata"
+  # set the next varialble to true to allows the system admin use this as a method for direct participation
+  workflow.ephemerable = true
+end
+```
+
+**IMPORANT**
+The following assumptions are made:
+- The verification workflow is responsible for making users accept the TOS.
+- The verification workflow is redirecting to `authorizations_path` or `redirect_url` after creating the authorization.
+
+## Contributing
+
+See [Decidim
+Barcelona](https://github.com/AjuntamentdeBarcelona/decidim-barcelona).
+
+## License
+
+See [Decidim
+Barcelona](https://github.com/AjuntamentdeBarcelona/decidim-barcelona).
diff --git a/decidim-ephemeral_participation/app/cells/decidim/ephemeral_participation/project_list_item_cell_override.rb b/decidim-ephemeral_participation/app/cells/decidim/ephemeral_participation/project_list_item_cell_override.rb
new file mode 100644
index 0000000000..8c58734004
--- /dev/null
+++ b/decidim-ephemeral_participation/app/cells/decidim/ephemeral_participation/project_list_item_cell_override.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    module ProjectListItemCellOverride
+      def vote_button_disabled?
+        return unless current_user
+        return if current_user.ephemeral_participant?
+
+        !can_have_order?
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/create_ephemeral_participant.rb b/decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/create_ephemeral_participant.rb
new file mode 100644
index 0000000000..094ba78a63
--- /dev/null
+++ b/decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/create_ephemeral_participant.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    class CreateEphemeralParticipant < Rectify::Command
+      include ::Devise::Controllers::Helpers
+
+      def initialize(request, current_user)
+        @request = request
+        @current_user = current_user
+      end
+
+      def call
+        return broadcast(:invalid) unless valid_params?
+
+        sign_in(new_ephemeral_participant) unless @current_user
+
+        broadcast(:ok, authorization_path)
+      end
+
+      private
+
+      def valid_params?
+        @request.is_a?(ActionDispatch::Request) && component_id.present? && ephemeral_participation_path.present?
+      end
+
+      def component_id
+        @request.params[:component_id]
+      end
+
+      def ephemeral_participation_path
+        @request.params[:ephemeral_participation_path]
+      end
+
+      def new_ephemeral_participant
+        Decidim::User.new(
+          organization: component.organization,
+          managed: true,
+          tos_agreement: true,
+          extended_data: {
+            ephemeral_participation: {
+              authorization_name: authorization_name,
+              component_id: component.id,
+              permissions:  component.ephemeral_participation_permissions,
+              request_path: ephemeral_participation_path
+            }
+          }
+        ).tap do |user|
+          user.nickname = nicknamize(user)
+          user.save!
+        end
+      end
+
+      # nickname is needed to ensure some links are not broken
+      def nicknamize(user)
+        Decidim::UserBaseEntity.nicknamize(user.name, organization: user.organization)
+      end
+
+      def authorization_path
+        adapter.root_path(redirect_url: ephemeral_participation_path)
+      end
+
+      def adapter
+        @adapter ||= Decidim::Verifications::Adapter.from_element(authorization_name)
+      end
+
+      def authorization_name
+        component.organization.ephemeral_participation_authorization
+      end
+
+      def component
+        @component ||= Decidim::Component.find(component_id)
+      end
+
+      # Needed for Devise::Controllers::Helpers#sign_in
+      def session
+        @request.session
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/destroy_ephemeral_participant.rb b/decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/destroy_ephemeral_participant.rb
new file mode 100644
index 0000000000..63e06f9cc7
--- /dev/null
+++ b/decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/destroy_ephemeral_participant.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    class DestroyEphemeralParticipant < Rectify::Command
+      include ::Devise::Controllers::Helpers
+
+      def initialize(request, user)
+        @request = request
+        @user = user
+      end
+
+      def call
+        return broadcast(:invalid) unless valid_params?
+
+        @user.invalidate_all_sessions!
+        @user.destroy! if destroy_user?
+        sign_out(@user)
+
+        broadcast(:ok)
+      end
+
+      private
+
+      def valid_params?
+        @request.is_a?(ActionDispatch::Request) && @user.is_a?(Decidim::User)
+      end
+
+      def destroy_user?
+        return false if @user.verified_ephemeral_participant?
+        return false if verification_conflicts.any?
+
+        true
+      end
+
+      def verification_conflicts
+        Decidim::Verifications::Conflict.where(current_user: @user)
+      end
+
+      # Needed for Devise::Controllers::Helpers#sign_out
+      def session
+        @request.session
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/transfer_ephemeral_participant.rb b/decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/transfer_ephemeral_participant.rb
new file mode 100644
index 0000000000..66f27b8e77
--- /dev/null
+++ b/decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/transfer_ephemeral_participant.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    class TransferEphemeralParticipant < Rectify::Command
+      def initialize(verified_user, unverifiable_user, form)
+        @verified_user     = verified_user
+        @unverifiable_user = unverifiable_user
+        @form              = form
+      end
+
+      def call
+        return broadcast(:invalid) unless valid_params?
+        
+        update_verified_user
+        update_unverifiable_user
+
+        broadcast(:ok)
+      end
+
+      private
+
+      def valid_params?
+        @verified_user.verified_ephemeral_participant?
+      end
+
+
+      def update_verified_user
+        @verified_user.session_token = SecureRandom.hex
+        @verified_user.managed = false
+        
+        @verified_user.email = @form.email
+
+        @verified_user.skip_reconfirmation!
+        @verified_user.save!
+        @verified_user.send_reset_password_instructions
+      end
+
+      def update_unverifiable_user
+        Decidim::DestroyAccount.call(
+          @unverifiable_user,
+          Decidim::DeleteAccountForm.from_params(reason: @form.reason),
+        )
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/transfer_user_override.rb b/decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/transfer_user_override.rb
new file mode 100644
index 0000000000..ab9080ac57
--- /dev/null
+++ b/decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/transfer_user_override.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    module TransferUserOverride
+      extend ActiveSupport::Concern
+
+      included do
+        alias :update_regular_managed_user :update_managed_user
+
+        private
+
+        def update_managed_user
+          if managed_user.verified_ephemeral_participant?
+            Decidim::EphemeralParticipation::TransferEphemeralParticipant.call(managed_user, new_user, form)
+          else
+            update_regular_managed_user
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/update_ephemeral_participant.rb b/decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/update_ephemeral_participant.rb
new file mode 100644
index 0000000000..1544fa9487
--- /dev/null
+++ b/decidim-ephemeral_participation/app/commands/decidim/ephemeral_participation/update_ephemeral_participant.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    class UpdateEphemeralParticipant < Rectify::Command
+      include ::Devise::Controllers::Helpers
+
+      def initialize(request, user, form)
+        @request = request
+        @user = user
+        @form = form
+      end
+
+      def call
+        return broadcast(:invalid) unless valid_params?
+        
+        update_user
+        bypass_sign_in(@user)
+
+        broadcast(:ok)
+      end
+
+      private
+
+      def valid_params?
+        @request.is_a?(ActionDispatch::Request) && @user.is_a?(Decidim::User) && @form.valid?
+      end
+
+      def update_user
+        @user.managed  = false
+        @user.accepted_tos_version = @user.organization.tos_version
+
+        @user.name     = @form.name
+        @user.nickname = @form.nickname
+        @user.email    = @form.email
+        @user.password = @form.password
+        @user.password_confirmation = @form.password_confirmation
+        @user.password_confirmation = @form.password_confirmation
+
+        @user.skip_reconfirmation!
+        @user.save!
+        @user.send(:after_confirmation)
+      end
+
+      # Needed for Devise::Controllers::Helpers#bypass_sign_in
+      def session
+        @request.session
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/controllers/concerns/decidim/ephemeral_participation/ephemeral_participable.rb b/decidim-ephemeral_participation/app/controllers/concerns/decidim/ephemeral_participation/ephemeral_participable.rb
new file mode 100644
index 0000000000..960fdd5c2c
--- /dev/null
+++ b/decidim-ephemeral_participation/app/controllers/concerns/decidim/ephemeral_participation/ephemeral_participable.rb
@@ -0,0 +1,97 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    module EphemeralParticipable
+      extend ActiveSupport::Concern
+
+      included do
+
+        before_action :destroy_ephemeral_participant,  if: :ephemeral_participant_session?
+        before_action :redirect_ephemeral_participant, if: :ephemeral_participant_session?
+        before_action :inform_ephemeral_participant,   if: :ephemeral_participant_session?
+
+        private
+
+        def ephemeral_participant_session?
+          current_user && current_user.ephemeral_participant?
+        end
+
+        def destroy_ephemeral_participant
+          return end_unverifiable_ephemeral_participant_session if end_unverifiable_ephemeral_participant_session?
+          return end_expired_ephemeral_participant_session      if end_expired_ephemeral_participant_session?
+        end
+
+        def end_unverifiable_ephemeral_participant_session
+          Decidim::EphemeralParticipation::DestroyEphemeralParticipant.call(request, current_user) do
+            on(:ok) do
+              flash[:alert] = I18n.t("unverifiable", scope: "decidim.ephemeral_participation.ephemeral_participants")
+
+              redirect_to(Decidim::Core::Engine.routes.url_helpers.root_path)
+            end
+          end
+        end
+
+        def end_unverifiable_ephemeral_participant_session?
+          current_user.unverifiable_ephemeral_participant?
+        end
+
+        def end_expired_ephemeral_participant_session
+          Decidim::EphemeralParticipation::DestroyEphemeralParticipant.call(request, current_user) do
+            on(:ok) do
+              flash[:notice] = I18n.t("destroy", scope: "decidim.ephemeral_participation.ephemeral_participants")
+
+              redirect_to(Decidim::Core::Engine.routes.url_helpers.root_path)
+            end
+          end
+        end
+
+        def end_expired_ephemeral_participant_session?
+          Decidim::EphemeralParticipation::SessionPresenter.new(current_user, helpers).ephemeral_participant_session_expired?
+        end
+
+        def redirect_ephemeral_participant
+          return redirect_to(ephemeral_participation_path)                  if redirect_to_ephemeral_participation_path?
+          return redirect_to(edit_ephemeral_participant_path(current_user)) if redirect_to_edit_ephemeral_participant_path?
+        end
+
+        def ephemeral_participation_path
+          current_user.ephemeral_participation_data["request_path"]
+        end
+
+        def redirect_to_ephemeral_participation_path?
+          Decidim::EphemeralParticipation::RedirectionRecognizer.new(request, current_user).redirect_to_ephemeral_participation_path?
+        end
+
+        def edit_ephemeral_participant_path(current_user)
+          Decidim::EphemeralParticipation::Engine.routes.url_helpers.edit_ephemeral_participant_path(current_user)
+        end
+
+        def redirect_to_edit_ephemeral_participant_path?
+          Decidim::EphemeralParticipation::RedirectionRecognizer.new(request, current_user).redirect_to_edit_ephemeral_participant_path?
+        end
+
+        def inform_ephemeral_participant
+          return (flash.now[:warning] = unverified_ephemeral_participant_message) if inform_unverified_ephemeral_participant?
+          return (flash.now[:warning] = verified_ephemeral_participant_message)   if inform_verified_ephemeral_participant?
+        end
+
+        def unverified_ephemeral_participant_message
+          Decidim::EphemeralParticipation::FlashMessagesPresenter.new(current_user, helpers).unverified_ephemeral_participant_message
+        end
+
+        def inform_unverified_ephemeral_participant?
+          Decidim::EphemeralParticipation::InformingRecognizer.new(request, current_user).inform_unverified_ephemeral_participant?
+        end
+
+        def verified_ephemeral_participant_message
+          Decidim::EphemeralParticipation::FlashMessagesPresenter.new(current_user, helpers).verified_ephemeral_participant_message
+        end
+
+        def inform_verified_ephemeral_participant?
+          Decidim::EphemeralParticipation::InformingRecognizer.new(request, current_user).inform_verified_ephemeral_participant?
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/controllers/concerns/decidim/ephemeral_participation/needs_permission_override.rb b/decidim-ephemeral_participation/app/controllers/concerns/decidim/ephemeral_participation/needs_permission_override.rb
new file mode 100644
index 0000000000..1e9499abba
--- /dev/null
+++ b/decidim-ephemeral_participation/app/controllers/concerns/decidim/ephemeral_participation/needs_permission_override.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    module NeedsPermissionOverride
+      extend ActiveSupport::Concern
+
+      included do
+        alias :old_user_has_no_permission  :user_has_no_permission
+        alias :old_permissions_context     :permissions_context
+
+        def user_has_no_permission
+          if request.xhr?
+            new_user_has_no_permission
+          else
+            old_user_has_no_permission
+          end
+        end
+
+        def permissions_context
+          old_permissions_context.merge(request: request)
+        end
+
+        private
+
+        def new_user_has_no_permission
+          render(js: unauthorized_error_flash_message_js)
+        end
+
+        def unauthorized_error_flash_message_js
+          <<~JAVASCRIPT
+            $alertBoxParsedHtml = $.parseHTML('#{unauthorized_error_flash_message_html}')[0].outerHTML;
+            alertBoxNotFound    = $('#content').html().indexOf($alertBoxParsedHtml) == -1;
+
+            if (alertBoxNotFound) $('#content').prepend($alertBoxParsedHtml);
+
+            $(window).scrollTop(0);
+          JAVASCRIPT
+        end
+
+        def unauthorized_error_flash_message_html
+          flash.clear
+
+          flash.now[:alert] = unauthorized_message
+
+          helpers.display_flash_messages
+        end
+
+        def unauthorized_message
+          if (current_user && current_user.ephemeral_participant?)
+            unauthorized_ephemeral_participant_message
+          else
+            I18n.t("actions.unauthorized", scope: "decidim.core")
+          end
+        end
+
+        def unauthorized_ephemeral_participant_message
+          presenter = Decidim::EphemeralParticipation::FlashMessagesPresenter.new(current_user, helpers)
+
+          if current_user.verified_ephemeral_participant?
+            presenter.unverified_ephemeral_participant_message
+          else
+            presenter.unauthorized_ephemeral_participant_message
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/controllers/decidim/ephemeral_participation/application_controller_override.rb b/decidim-ephemeral_participation/app/controllers/decidim/ephemeral_participation/application_controller_override.rb
new file mode 100644
index 0000000000..d70eb6addf
--- /dev/null
+++ b/decidim-ephemeral_participation/app/controllers/decidim/ephemeral_participation/application_controller_override.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    module ApplicationControllerOverride
+      extend ActiveSupport::Concern
+
+      included do
+        include Decidim::EphemeralParticipation::EphemeralParticipable
+        include Decidim::EphemeralParticipation::NeedsPermissionOverride
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/controllers/decidim/ephemeral_participation/conflicts_controller_override.rb b/decidim-ephemeral_participation/app/controllers/decidim/ephemeral_participation/conflicts_controller_override.rb
new file mode 100644
index 0000000000..4717e865ec
--- /dev/null
+++ b/decidim-ephemeral_participation/app/controllers/decidim/ephemeral_participation/conflicts_controller_override.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    module ConflictsControllerOverride
+      extend ActiveSupport::Concern
+
+      included do
+        # TEMPORARY OVERRIDE TO RENDER FORM ON ERROR (BUG IN DECIDIM)
+        # https://github.com/decidim/decidim/blob/00bad01ccfa95473fd2d7b2f2cb1919623295ba3/decidim-admin/app/controllers/decidim/admin/conflicts_controller.rb#L40
+        def update
+          conflict = Decidim::Verifications::Conflict.find(params[:id])
+
+          @form = form(Decidim::Admin::TransferUserForm).from_params(
+            current_user: current_user,
+            conflict: conflict,
+            reason: params[:transfer_user][:reason],
+            email: params[:transfer_user][:email]
+          )
+
+          Decidim::Admin::TransferUser.call(@form) do
+            on(:ok) do
+              flash[:notice] = I18n.t("success", scope: "decidim.admin.conflicts.transfer")
+              redirect_to conflicts_path
+            end
+
+            on(:invalid) do
+              flash.now[:alert] = I18n.t("error", scope: "decidim.admin.conflicts.transfer")
+              render :edit
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/controllers/decidim/ephemeral_participation/ephemeral_participants_controller.rb b/decidim-ephemeral_participation/app/controllers/decidim/ephemeral_participation/ephemeral_participants_controller.rb
new file mode 100644
index 0000000000..4300081950
--- /dev/null
+++ b/decidim-ephemeral_participation/app/controllers/decidim/ephemeral_participation/ephemeral_participants_controller.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    class EphemeralParticipantsController < Decidim::ApplicationController
+      include FormFactory
+
+      def create
+        enforce_permission_to(:create, :ephemeral_participant)
+
+        Decidim::EphemeralParticipation::CreateEphemeralParticipant.call(request, current_user) do
+          on(:ok) do |authorization_path|
+            flash[:notice] = I18n.t("create", scope: "decidim.ephemeral_participation.ephemeral_participants")
+
+            redirect_to(authorization_path)
+          end
+
+          on(:invalid) do
+            render template: "decidim/errors/not_found", locals: { root_path: decidim_root_path }
+          end
+        end
+      end
+
+      def edit
+        enforce_permission_to(:update, :ephemeral_participant, current_user: current_user)
+
+        @form = form(EphemeralParticipantForm).from_model(current_user)
+
+        render(layout: "layouts/decidim/ephemeral_participation/user_profile")
+      end
+
+      def update
+        enforce_permission_to(:update, :ephemeral_participant, current_user: current_user)
+
+        @form = form(EphemeralParticipantForm).from_params(params)
+
+        Decidim::EphemeralParticipation::UpdateEphemeralParticipant.call(request, current_user, @form) do
+          on(:ok) do
+            flash[:notice] = I18n.t("update.success", scope: "decidim.ephemeral_participation.ephemeral_participants")
+
+            redirect_to(decidim.account_path)
+          end
+
+          on(:invalid) do
+            flash[:alert] = I18n.t("update.error", scope: "decidim.ephemeral_participation.ephemeral_participants")
+
+            render(action: :edit)
+          end
+        end
+      end
+
+      def destroy
+        enforce_permission_to(:destroy, :ephemeral_participant, current_user: current_user)
+
+        Decidim::EphemeralParticipation::DestroyEphemeralParticipant.call(request, current_user) do
+          on(:ok) do
+            flash[:notice] = I18n.t("destroy", scope: "decidim.ephemeral_participation.ephemeral_participants")
+
+            redirect_to(decidim_root_path)
+          end
+        end
+      end
+
+      private
+
+      def decidim_root_path
+        Decidim::Core::Engine.routes.url_helpers.root_path
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/component_form_override.rb b/decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/component_form_override.rb
new file mode 100644
index 0000000000..bd44357c6a
--- /dev/null
+++ b/decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/component_form_override.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    module ComponentFormOverride
+      extend ActiveSupport::Concern
+
+      included do
+        validate  :validate_ephemeral_participation_enabled
+
+        private
+
+        def validate_ephemeral_participation_enabled
+          return unless settings.try(:ephemeral_participation_enabled) == true
+          return if participatory_space.organization.ephemeral_participation_authorization
+
+          settings.errors.add(:ephemeral_participation_enabled, :missing_ephemeral_participation_authorization)
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/ephemeral_participant_form.rb b/decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/ephemeral_participant_form.rb
new file mode 100644
index 0000000000..72eecf0469
--- /dev/null
+++ b/decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/ephemeral_participant_form.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    class EphemeralParticipantForm < Decidim::Form
+      mimic :ephemeral_participant
+
+      attribute :name
+      attribute :nickname
+      attribute :email
+      attribute :password
+      attribute :password_confirmation
+
+      validates :name, presence: true
+      validates :email, presence: true, 'valid_email_2/email': { disposable: true }
+      validates :nickname, presence: true, format: Decidim::User::REGEXP_NICKNAME
+      validates :nickname, length: { maximum: Decidim::User.nickname_max_length, allow_blank: true }
+      validates :password, presence: true, confirmation: true
+      validates :password, password: { name: :name, email: :email, username: :nickname }
+      validates :password_confirmation, presence: true
+
+      validate :unique_email
+      validate :unique_nickname
+
+      alias organization current_organization
+
+      private
+
+      def unique_email
+        return if duplicates(email: email).none?
+
+        errors.add(:email, :taken)
+      end
+
+      def unique_nickname
+        return if duplicates(nickname: nickname).none?
+
+        errors.add(:nickname, :taken)
+      end
+
+      def duplicates(where_clause)
+        Decidim::EphemeralParticipation::DuplicatedUsers.new(
+          organization: current_organization,
+          excluding: current_user,
+          where_clause: where_clause,
+        ).query
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/permissions_form_override.rb b/decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/permissions_form_override.rb
new file mode 100644
index 0000000000..1d813359b0
--- /dev/null
+++ b/decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/permissions_form_override.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    module PermissionsFormOverride
+      extend ActiveSupport::Concern
+
+      included do
+        attribute :component_id,  String
+        attribute :resource_id,   String
+
+        validate  :validate_ephemeral_participation_permissions_settings
+
+        private
+
+        def validate_ephemeral_participation_permissions_settings
+          return if     resource_permissions?
+          return unless ephemeral_participation_enabled?
+
+          permissions.values.each do |permission_form|
+            next if valid_permission_form?(permission_form)
+
+            permission_form.errors.add(:base, :invalid_ephemeral_participation_permissions, i18n_options)
+          end
+        end
+
+        def resource_permissions?
+          resource_id.present?
+        end
+
+        def ephemeral_participation_enabled?
+          component.ephemeral_participation_enabled?
+        end
+
+        def valid_permission_form?(permission_form)
+          handler_names = permission_form.authorization_handlers.keys & component.organization.available_authorizations
+
+          handler_names.exclude?(component.organization.ephemeral_participation_authorization) || handler_names.size == 1
+        end
+
+        def component
+          @component ||= Decidim::Component.find(component_id)
+        end
+
+        def i18n_options
+          {
+            ephemeral_participation_authorization: I18n.t("decidim.authorization_handlers.#{component.organization.ephemeral_participation_authorization}.name"),
+            ephemeral_participation_enabled: I18n.t("decidim.components.#{component.manifest_name}.settings.global.ephemeral_participation_enabled"),
+          }
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/transfer_user_form_override.rb b/decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/transfer_user_form_override.rb
new file mode 100644
index 0000000000..e3c36c236c
--- /dev/null
+++ b/decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/transfer_user_form_override.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    module TransferUserFormOverride
+      extend ActiveSupport::Concern
+
+      included do
+        validate :unique_email
+
+        private
+
+        def unique_email
+          return if duplicates(email: email).none?
+
+          errors.add(:email, :taken)
+        end
+
+        def duplicates(where_clause)
+          Decidim::EphemeralParticipation::DuplicatedUsers.new(
+            organization: current_user.organization,
+            where_clause: where_clause,
+          ).query
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/update_organization_form_override.rb b/decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/update_organization_form_override.rb
new file mode 100644
index 0000000000..d836c03281
--- /dev/null
+++ b/decidim-ephemeral_participation/app/forms/decidim/ephemeral_participation/update_organization_form_override.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    module UpdateOrganizationFormOverride
+      extend ActiveSupport::Concern
+
+      included do
+        alias :old_map_model :map_model
+
+        attribute :available_authorizations, Object
+
+        validate  :validate_available_authorizations
+
+        def map_model(model)
+          old_map_model(model)
+          new_map_model(model)
+        end
+
+        def new_map_model(model)
+          self.available_authorizations = model.read_attribute(:available_authorizations)
+          self.available_authorizations = self.available_authorizations.map { |a| [a, {}] }.to_h if self.available_authorizations.is_a?(Array)
+        end
+
+        def clean_available_authorizations
+          available_authorizations
+        end
+
+        def before_validation
+          available_authorizations.transform_values! { |string| JSON.parse(string).presence }.compact!
+        end
+
+        private
+
+        def validate_available_authorizations
+          return unless available_authorizations.values.count { |hash| hash["allow_ephemeral_participation"] == true } > 1
+
+          errors.add(:available_authorizations, :invalid)
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/models/decidim/ephemeral_participation/component_override.rb b/decidim-ephemeral_participation/app/models/decidim/ephemeral_participation/component_override.rb
new file mode 100644
index 0000000000..1321c5cc50
--- /dev/null
+++ b/decidim-ephemeral_participation/app/models/decidim/ephemeral_participation/component_override.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    module ComponentOverride
+      extend ActiveSupport::Concern
+
+      included do
+        def ephemeral_participation_enabled?
+          settings.try(:ephemeral_participation_enabled) == true
+        end
+        
+        # Given organization.ephemeral_participation_authorization == "valid_auth"
+        # permissions => {"vote"=>{"authorization_handlers"=>{"valid_auth"=>{}}}}
+        # ephemeral_participation_permissions => ["vote"]
+        def ephemeral_participation_permissions
+          @ephemeral_participation_permissions ||= begin
+            return [] unless ephemeral_participation_enabled?
+            return [] unless permissions.present?
+            
+            permissions.map do |action, authorization_handlers|
+              handler_names = authorization_handlers.values.flat_map(&:keys)
+
+              action if handler_names.include?(organization.ephemeral_participation_authorization)
+            end.compact
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/models/decidim/ephemeral_participation/organization_override.rb b/decidim-ephemeral_participation/app/models/decidim/ephemeral_participation/organization_override.rb
new file mode 100644
index 0000000000..520ef4fbf5
--- /dev/null
+++ b/decidim-ephemeral_participation/app/models/decidim/ephemeral_participation/organization_override.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    module OrganizationOverride
+      extend ActiveSupport::Concern
+
+      included do
+        # altough this might introduce some confusion it maintains compatibility accross the application
+        # for any code expecting to obtain an array
+        def available_authorizations
+          authorizations = read_attribute(:available_authorizations)
+          authorizations.is_a?(Array) ? authorizations : authorizations.keys
+        end
+
+        def ephemeral_participation_authorization
+          read_attribute(:available_authorizations).key("allow_ephemeral_participation" => true)
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/models/decidim/ephemeral_participation/permission_action_override.rb b/decidim-ephemeral_participation/app/models/decidim/ephemeral_participation/permission_action_override.rb
new file mode 100644
index 0000000000..c4fba8aead
--- /dev/null
+++ b/decidim-ephemeral_participation/app/models/decidim/ephemeral_participation/permission_action_override.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    module PermissionActionOverride
+      extend ActiveSupport::Concern
+
+      included do
+        def disallowed?
+          @state == :disallowed
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/models/decidim/ephemeral_participation/user_override.rb b/decidim-ephemeral_participation/app/models/decidim/ephemeral_participation/user_override.rb
new file mode 100644
index 0000000000..12280e4f93
--- /dev/null
+++ b/decidim-ephemeral_participation/app/models/decidim/ephemeral_participation/user_override.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    module UserOverride
+      extend ActiveSupport::Concern
+
+      included do
+        scope :ephemeral_participant, -> { managed.where("extended_data ? 'ephemeral_participation'") }
+
+        def ephemeral_participant?
+          managed? && ephemeral_participation_data.present?
+        end
+
+        def ephemeral_participation_data
+          extended_data.fetch("ephemeral_participation", {})
+        end
+
+        def verified_ephemeral_participant?
+          return false unless ephemeral_participant?
+
+          Decidim::Authorization.exists?(
+            user: self,
+            name: ephemeral_participation_data["authorization_name"]
+          )
+        end
+
+        def verifiable_ephemeral_participant?
+          return false unless ephemeral_participant?
+
+          Decidim::EphemeralParticipation::VerificationConflicts.for(self).none?
+        end
+
+        def unverifiable_ephemeral_participant?
+          return false unless ephemeral_participant?
+
+          Decidim::EphemeralParticipation::VerificationConflicts.for(self).any?
+        end
+
+        def ephemeral_participation_verification_adapter
+          return nil unless ephemeral_participant?
+
+          Decidim::Verifications::Adapter.from_element(ephemeral_participation_data["authorization_name"])
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/permissions/decidim/ephemeral_participation/ephemeral_action_permissions_dictionary.rb b/decidim-ephemeral_participation/app/permissions/decidim/ephemeral_participation/ephemeral_action_permissions_dictionary.rb
new file mode 100644
index 0000000000..4e327300a6
--- /dev/null
+++ b/decidim-ephemeral_participation/app/permissions/decidim/ephemeral_participation/ephemeral_action_permissions_dictionary.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    class EphemeralActionPermissionsDictionary
+      COMPONENT_PERMISSIONS_DICTIONARY = {
+        "budgets" => {
+          "vote" => [
+            { action: :vote,   scope: :public, subject: :project },
+            { action: :create, scope: :public, subject: :order },
+          ]
+        }
+      }
+
+      def self.for(component)
+        new(component).fetch
+      end
+
+      def initialize(component)
+        @component = component
+      end
+
+      def fetch
+        return {} unless @component && @component.ephemeral_participation_permissions.any?
+
+        COMPONENT_PERMISSIONS_DICTIONARY.fetch(@component.manifest_name).select do |action, _|
+          @component.ephemeral_participation_permissions.include?(action)
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/permissions/decidim/ephemeral_participation/ephemeral_participation_permissions.rb b/decidim-ephemeral_participation/app/permissions/decidim/ephemeral_participation/ephemeral_participation_permissions.rb
new file mode 100644
index 0000000000..3175cc8cfc
--- /dev/null
+++ b/decidim-ephemeral_participation/app/permissions/decidim/ephemeral_participation/ephemeral_participation_permissions.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: true
+
+require_relative "ephemeral_action_permissions_dictionary"
+
+module Decidim
+  module EphemeralParticipation
+    class EphemeralParticipationPermissions < DefaultPermissions
+      def permissions
+        return permission_action if regular_user?
+        return permission_action if permission_action.disallowed?
+
+        if create_ephemeral_participant?
+          allow!    if allowed_to_create_ephemeral_participant?
+        elsif update_ephemeral_participant?
+          allow!    if allowed_to_update_ephemeral_participant?
+        elsif destroy_ephemeral_participant?
+          allow!    if allowed_to_destroy_ephemeral_participant?
+        elsif update_profile?
+          disallow! unless allowed_to_update_profile?
+        else
+          disallow! unless allowed_ephemeral_participation?
+        end
+
+        permission_action
+      end
+
+      private
+
+      def regular_user?
+        user && (not user.ephemeral_participant?)
+      end
+
+      def create_ephemeral_participant?
+        permission_action.action == :create &&
+          permission_action.scope == :public &&
+            permission_action.subject == :ephemeral_participant
+      end
+
+      def allowed_to_create_ephemeral_participant?
+        return true if user.nil?
+        return true if (not user.verified_ephemeral_participant?)
+        
+        false
+      end
+
+      def destroy_ephemeral_participant?
+        permission_action.action == :destroy &&
+        permission_action.scope == :public &&
+          permission_action.subject == :ephemeral_participant
+      end
+
+      def allowed_to_destroy_ephemeral_participant?
+        user && user == context[:current_user]
+      end
+
+      def update_ephemeral_participant?
+        permission_action.action == :update &&
+        permission_action.scope == :public &&
+          permission_action.subject == :ephemeral_participant
+      end
+
+      def allowed_to_update_ephemeral_participant?
+        user && user == context[:current_user] && user.verifiable_ephemeral_participant?
+      end
+
+      def update_profile?
+        permission_action.action == :update_profile &&
+          permission_action.scope == :public &&
+            permission_action.subject == :user
+      end
+
+      def allowed_to_update_profile?
+        verify_ephemeral_participant_path? && (not user.verified_ephemeral_participant?)
+      end
+
+      def verify_ephemeral_participant_path?
+        Decidim::EphemeralParticipation::InformingRecognizer.new(context[:request], user).verify_ephemeral_participant_path?
+      end
+
+      def decidim_verifiations
+        Decidim::Verifications::Engine.routes.url_helpers
+      end
+
+      def allowed_ephemeral_participation?
+        return true if browsing_public_pages?
+        return true if changing_locales?
+        return true if user && user.verified_ephemeral_participant? && ephemeral_participation_permission_action?
+
+        false
+      end
+
+      def browsing_public_pages?
+        permission_action.scope == :public && [:read, :list].include?(permission_action.action)
+      end
+
+      def changing_locales?
+        permission_action.action == :create &&
+          permission_action.scope == :public &&
+            permission_action.subject == :locales
+      end
+
+      def ephemeral_participation_permission_action?
+        Decidim::EphemeralParticipation::EphemeralActionPermissionsDictionary.for(component)
+          .any? do |_, permission_action_attributes|
+            permission_action_attributes.any? do |action:, scope:, subject:|
+              permission_action.matches?(scope, action, subject)
+            end
+          end
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/permissions/decidim/ephemeral_participation/permissions_override.rb b/decidim-ephemeral_participation/app/permissions/decidim/ephemeral_participation/permissions_override.rb
new file mode 100644
index 0000000000..b0d7377c9c
--- /dev/null
+++ b/decidim-ephemeral_participation/app/permissions/decidim/ephemeral_participation/permissions_override.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    module PermissionsOverride
+      extend ActiveSupport::Concern
+
+      included do
+        alias :old_permissions :permissions
+
+        def permissions
+          old_permissions
+          new_permissions
+        end
+
+        private
+
+        def new_permissions
+          Decidim::EphemeralParticipation::EphemeralParticipationPermissions.new(user, permission_action, context).permissions
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/presenter/decidim/ephemeral_participation/flash_messages_presenter.rb b/decidim-ephemeral_participation/app/presenter/decidim/ephemeral_participation/flash_messages_presenter.rb
new file mode 100644
index 0000000000..428b7ebdfa
--- /dev/null
+++ b/decidim-ephemeral_participation/app/presenter/decidim/ephemeral_participation/flash_messages_presenter.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    class FlashMessagesPresenter
+      def initialize(user, view_helpers)
+        @user = user
+        @view_helpers = view_helpers
+      end
+
+      def unauthorized_ephemeral_participant_message
+        I18n.t(
+          "decidim.ephemeral_participation.actions.unauthorized",
+          link: (
+            @view_helpers.link_to(
+              I18n.t("decidim.ephemeral_participation.actions.unauthorized_link"),
+              decidim_ephemeral_participation.edit_ephemeral_participant_path(@user),
+            )
+          )
+        ).html_safe
+      end
+
+      def verified_ephemeral_participant_message
+        I18n.t(
+          "decidim.ephemeral_participation.actions.verified",
+          link: @view_helpers.link_to(
+            I18n.t("decidim.ephemeral_participation.actions.verified_link"),
+              decidim_ephemeral_participation.edit_ephemeral_participant_path(@user),
+          )
+        ).html_safe
+      end
+
+      def edit_ephemeral_participant_path
+        Decidim::EphemeralParticipation::Engine.routes.url_helpers.edit_ephemeral_participant_path(@user)
+      end
+
+      def unverified_ephemeral_participant_message
+        I18n.t(
+          "decidim.ephemeral_participation.actions.unverified",
+          link: @view_helpers.link_to(
+            I18n.t("decidim.ephemeral_participation.actions.unverified_link"),
+            verify_ephemeral_participant_path,
+          )
+        ).html_safe
+      end
+
+      def verify_ephemeral_participant_path
+        @user
+          .ephemeral_participation_verification_adapter
+          .root_path(redirect_url: @user.ephemeral_participation_data["request_path"])
+      end
+
+      def decidim_ephemeral_participation
+        Decidim::EphemeralParticipation::Engine.routes.url_helpers
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/presenter/decidim/ephemeral_participation/session_presenter.rb b/decidim-ephemeral_participation/app/presenter/decidim/ephemeral_participation/session_presenter.rb
new file mode 100644
index 0000000000..d817907e48
--- /dev/null
+++ b/decidim-ephemeral_participation/app/presenter/decidim/ephemeral_participation/session_presenter.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    class SessionPresenter
+      EPHEMERAL_PARTICIPANT_SESSION_DURATION = 30.minutes
+
+      def initialize(user, view_helpers)
+        @user = user
+        @view_helpers = view_helpers
+      end
+
+      def ephemeral_participant_session_remaining_time_in_minutes
+        (ephemeral_participant_session_remaining_time / 1.minute).round
+      end
+
+      def ephemeral_participant_session_expired?
+        ephemeral_participant_session_remaining_time.negative?
+      end
+
+      private
+
+      def ephemeral_participant_session_remaining_time
+        (@user.created_at + EPHEMERAL_PARTICIPANT_SESSION_DURATION) - Time.current
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/queries/decidim/ephemeral_participation/duplicated_users.rb b/decidim-ephemeral_participation/app/queries/decidim/ephemeral_participation/duplicated_users.rb
new file mode 100644
index 0000000000..64dc2f757f
--- /dev/null
+++ b/decidim-ephemeral_participation/app/queries/decidim/ephemeral_participation/duplicated_users.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    class DuplicatedUsers < Rectify::Query
+      def initialize(organization:, excluding: nil, where_clause:)
+        @organization = organization
+        @excluding    = Array.wrap(excluding).compact.map(&:id)
+        @where_clause = where_clause
+      end
+
+      def query
+        Decidim::User
+          .where(organization: @organization)
+          .where.not(id: @excluding)
+          .where(**@where_clause)
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/queries/decidim/ephemeral_participation/verification_conflicts.rb b/decidim-ephemeral_participation/app/queries/decidim/ephemeral_participation/verification_conflicts.rb
new file mode 100644
index 0000000000..fc6645564a
--- /dev/null
+++ b/decidim-ephemeral_participation/app/queries/decidim/ephemeral_participation/verification_conflicts.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    class VerificationConflicts < Rectify::Query
+      def self.for(user)
+        new(user).query
+      end
+
+      def initialize(user)
+        @user = user
+      end
+
+      def query
+        Decidim::Verifications::Conflict.where(current_user: @user)
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/services/decidim/ephemeral_participation/informing_recognizer.rb b/decidim-ephemeral_participation/app/services/decidim/ephemeral_participation/informing_recognizer.rb
new file mode 100644
index 0000000000..3d896da887
--- /dev/null
+++ b/decidim-ephemeral_participation/app/services/decidim/ephemeral_participation/informing_recognizer.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    class InformingRecognizer
+      def initialize(request, user)
+        @request = request
+        @user = user
+      end
+
+      def inform_unverified_ephemeral_participant?
+        informable_ephemeral_participant? && (not @user.verified_ephemeral_participant?)
+      end
+      
+
+      def inform_verified_ephemeral_participant?
+        informable_ephemeral_participant? && @user.verified_ephemeral_participant?
+      end
+
+      def informable_ephemeral_participant?
+        return false if verify_ephemeral_participant_path?
+        return false if edit_ephemeral_participant_path?
+        return false if @request.flash.any?
+
+        true
+      end
+
+      def verify_ephemeral_participant_path?
+        adapter = @user.ephemeral_participation_verification_adapter
+        engine  = (adapter.type == "direct") ? Decidim::Verifications::Engine : adapter.engine
+
+        engine.routes.recognize_path_with_request(@request, @request.path, method: @request.method)
+      rescue ActionController::RoutingError
+        false
+      end
+
+      private
+
+      def edit_ephemeral_participant_path?
+        @request.path == edit_ephemeral_participant_path
+      end
+
+      def edit_ephemeral_participant_path
+        Decidim::EphemeralParticipation::FlashMessagesPresenter
+          .new(@user, nil)
+          .edit_ephemeral_participant_path
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/services/decidim/ephemeral_participation/redirection_recognizer.rb b/decidim-ephemeral_participation/app/services/decidim/ephemeral_participation/redirection_recognizer.rb
new file mode 100644
index 0000000000..dd5fdfa7ed
--- /dev/null
+++ b/decidim-ephemeral_participation/app/services/decidim/ephemeral_participation/redirection_recognizer.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    class RedirectionRecognizer
+      def initialize(request, user)
+        @request = request
+        @user = user
+      end
+
+      # Handles verification workflows redirecting to authorizations#index after creating authorization.
+      def redirect_to_ephemeral_participation_path?
+        @user.verified_ephemeral_participant? &&
+          @request.method == "GET" &&
+            @request.path == decidim_verifications.authorizations_path
+      end
+
+      def redirect_to_edit_ephemeral_participant_path?
+        return true if path?(decidim.account_path)
+        return true if path?(decidim.notifications_settings_path)
+        return true if path?(decidim.data_portability_path)
+        return true if path?(decidim.own_user_groups_path)
+        return true if path?(decidim.user_interests_path)
+        return true if path?(decidim.profile_path(@user.nickname))
+        return true if path?(decidim.notifications_path)
+        return true if path?(decidim.conversations_path)
+        
+        false
+      end
+
+      private
+
+      def path?(path)
+        @request.path.include?(path)
+      end
+
+      def decidim_verifications
+        Decidim::Verifications::Engine.routes.url_helpers
+      end
+
+      def decidim
+        Decidim::Core::Engine.routes.url_helpers
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/app/views/decidim/budgets/projects/_project_budget_button.html.erb b/decidim-ephemeral_participation/app/views/decidim/budgets/projects/_project_budget_button.html.erb
new file mode 100644
index 0000000000..10fef00ebb
--- /dev/null
+++ b/decidim-ephemeral_participation/app/views/decidim/budgets/projects/_project_budget_button.html.erb
@@ -0,0 +1,46 @@
+<div id="project-<%= project.id %>-budget-button">
+  <% if voted_for?(project) %>
+    <%= action_authorized_button_to(
+          "vote",
+          t(".added"),
+          budget_order_line_item_path(budget, project_id: project),
+          method: :delete,
+          remote: true,
+          data: {
+            disable: true,
+            budget: project.budget_amount,
+            "redirect-url": budget_project_path(budget, project)
+          },
+          disabled: !can_have_order? || current_order_checked_out?,
+          class: "button expanded button--sc success",
+          "aria-label": t(".added_descriptive", resource_name: translated_attribute(project.title))
+        ) %>
+  <% elsif current_user.present? && (!current_user.ephemeral_participant? || current_user.verified_ephemeral_participant?) %>
+    <%= action_authorized_button_to(
+          "vote",
+          t(".add"),
+          budget_order_line_item_path(budget, project_id: project),
+          method: :post,
+          remote: true,
+          data: {
+            disable: true,
+            budget: project.budget_amount,
+            add: true,
+            "redirect-url": budget_project_path(budget, project)
+          },
+          disabled: !can_have_order? || current_order_checked_out?,
+          class: "button expanded button--sc",
+          "aria-label": t(".add_descriptive", resource_name: translated_attribute(project.title))
+        ) %>
+  <% elsif current_user.present? && (current_user.ephemeral_participant? && !current_user.verified_ephemeral_participant?) %>
+    <%= link_to t(".add"),
+                Decidim::EphemeralParticipation::FlashMessagesPresenter.new(current_user, self).verify_ephemeral_participant_path,
+                class: "button expanded button--sc",
+                "aria-label": t(".add_descriptive", resource_name: translated_attribute(project.title))
+           %>
+  <% else %>
+    <button class="button expanded button--sc" data-toggle="loginModal">
+      <%= t(".add") %>
+    </button>
+  <% end %>
+</div>
diff --git a/decidim-ephemeral_participation/app/views/decidim/ephemeral_participation/ephemeral_participants/edit.html.erb b/decidim-ephemeral_participation/app/views/decidim/ephemeral_participation/ephemeral_participants/edit.html.erb
new file mode 100644
index 0000000000..b97f17a37c
--- /dev/null
+++ b/decidim-ephemeral_participation/app/views/decidim/ephemeral_participation/ephemeral_participants/edit.html.erb
@@ -0,0 +1,16 @@
+
+<div class="row">
+  <%= decidim_form_for(@form, url: ephemeral_participant_path, method: :put, html: { autocomplete: "off" }) do |form| %>
+    <input autocomplete="off" name="hidden" type="password" style="display:none;">
+    <div class="columns large-8 end">
+      <%= form.text_field :name %>
+      <%= form.text_field :nickname %>
+      <%= form.email_field :email %>
+
+      <%= form.password_field :password, value: form.object.password, autocomplete: "off", help_text: I18n.t("devise.passwords.edit.password_help", minimun_characters: NOBSPW.configuration.min_password_length) %>
+      <%= form.password_field :password_confirmation, value: form.object.password_confirmation, autocomplete: "off" %>
+
+      <%= form.submit I18n.t("submit", scope: "decidim.ephemeral_participation.ephemeral_participants") %>
+    </div>
+  <% end %>
+</div>
diff --git a/decidim-ephemeral_participation/app/views/decidim/ephemeral_participation/shared/_login_modal.erb b/decidim-ephemeral_participation/app/views/decidim/ephemeral_participation/shared/_login_modal.erb
new file mode 100644
index 0000000000..03b4c712c0
--- /dev/null
+++ b/decidim-ephemeral_participation/app/views/decidim/ephemeral_participation/shared/_login_modal.erb
@@ -0,0 +1,30 @@
+<%
+  if(
+    controller.respond_to?(:current_component) &&
+      current_component.ephemeral_participation_enabled? &&
+        current_component.ephemeral_participation_permissions.any?
+  )
+%>
+  <div class="row">
+    <div class="columns medium-8 medium-centered">
+      <span class="register__separator">
+        <span class="register__separator__text"><%= I18n.t("or", scope: "decidim.devise.shared.omniauth_buttons") %></span>
+      </span>
+      <div class="text-center">
+        <span class="register__separator">
+          <%=
+            button_to(
+              I18n.t("button", scope: "decidim.ephemeral_participation.login_modal"),
+              decidim_ephemeral_participation.ephemeral_participants_path(
+                component_id: current_component.id,
+                ephemeral_participation_path: request.path,
+              ),
+              class: "button expanded"
+            )
+          %>
+          <%= I18n.t("help", scope: "decidim.ephemeral_participation.login_modal") %>
+        </span>
+      </div>
+    </div>
+  </div>
+<% end %>
diff --git a/decidim-ephemeral_participation/app/views/decidim/shared/_login_modal.html.erb b/decidim-ephemeral_participation/app/views/decidim/shared/_login_modal.html.erb
new file mode 100644
index 0000000000..4bb53666da
--- /dev/null
+++ b/decidim-ephemeral_participation/app/views/decidim/shared/_login_modal.html.erb
@@ -0,0 +1,63 @@
+<div class="reveal" id="loginModal" data-reveal>
+  <div class="reveal__header">
+    <h2 class="reveal__title"><%= I18n.t("please_sign_in", scope: "decidim.shared.login_modal") %></h2>
+    <button class="close-button" data-close aria-label="<%= I18n.t("close_modal", scope: "decidim.shared.login_modal") %>"
+      type="button">
+      <span aria-hidden="true">&times;</span>
+    </button>
+  </div>
+  <% if current_organization.sign_in_enabled? %>
+    <div class="row">
+      <div class="columns medium-8 medium-centered">
+          <%
+            path = if content_for(:redirect_after_login)
+                     session_path(:user, redirect_url: content_for(:redirect_after_login))
+                   else
+                     session_path(:user)
+                   end
+          %>
+          <%= decidim_form_for(Decidim::User.new, namespace: "login", as: :user, url: path, html: { class: "register-form new_user" }) do |f| %>
+            <div>
+              <div class="field">
+                <%= f.email_field :email %>
+              </div>
+              <div class="field">
+                <%= f.password_field :password, autocomplete: "off" %>
+              </div>
+            </div>
+            <div class="actions">
+              <%= f.submit I18n.t("devise.sessions.new.sign_in"), class: "button expanded" %>
+            </div>
+          <% end %>
+          <% if current_organization.sign_up_enabled? %>
+            <p class="text-center">
+              <%= link_to I18n.t("sign_up", scope: "decidim.shared.login_modal"), decidim.new_user_registration_path, class: "sign-up-link" %>
+            </p>
+          <% end %>
+          <p class="text-center">
+            <%= link_to I18n.t("devise.shared.links.forgot_your_password"), new_password_path(:user) %>
+          </p>
+      </div>
+    </div>
+    <% cache current_organization do %>
+      <%= render "decidim/devise/shared/omniauth_buttons_mini" %>
+    <% end %>
+    <% cache current_organization do %>
+      <%= render "decidim/ephemeral_participation/shared/login_modal" %>
+    <% end %>
+  <% else %>
+    <div class="row">
+      <div class="columns medium-8 medium-centered">
+        <p>
+          <%= I18n.t("sign_in_disabled", scope: "decidim.devise.sessions.new") %>
+        </p>
+      </div>
+    </div>
+    <% cache current_organization do %>
+      <%= render "decidim/devise/shared/omniauth_buttons" %>
+    <% end %>
+    <% cache current_organization do %>
+      <%= render "decidim/ephemeral_participation/shared/login_modal" %>
+    <% end %>
+  <% end %>
+</div>
diff --git a/decidim-ephemeral_participation/app/views/decidim/system/organizations/_authorizations_settings.erb b/decidim-ephemeral_participation/app/views/decidim/system/organizations/_authorizations_settings.erb
new file mode 100644
index 0000000000..dd61d4ad5f
--- /dev/null
+++ b/decidim-ephemeral_participation/app/views/decidim/system/organizations/_authorizations_settings.erb
@@ -0,0 +1,61 @@
+<div class="fieldset">
+  <table class="stack">
+    <thead>
+      <tr>
+        <th><%= f.label :available_authorizations %></th>
+        <th><%= f.label :enabled %></th>
+        <th><%= f.label :allows_ephemeral_participation %></th>
+      </tr>
+    </thead>
+    <tbody>
+      <%= f.fields_for :available_authorizations, f.object.available_authorizations do |ff| %>
+        <%= f.error_for(:available_authorizations) %>
+        <% Decidim.authorization_workflows.each do |authorization_workflow| %>
+            <tr>
+              <td>
+                <%= ff.label authorization_workflow.description %>
+              </td>
+              <td> 
+                <%= ff.check_box(
+                      authorization_workflow.name, # attribute
+                      {
+                        label: false,
+                        id: "organization_available_authorizations_#{authorization_workflow.name}_enabled",
+                        checked: f.object.available_authorizations&.key?(authorization_workflow.name)
+                      }, # options
+                      { allow_ephemeral_participation: false }.to_json, # checked_value
+                      {}.to_json # unchecked_value
+                    ) %>
+              </td>
+              <td>
+                <%= ff.radio_button(
+                      authorization_workflow.name, # attribute
+                      { allow_ephemeral_participation: true }.to_json, # value
+                      {
+                        label: false,
+                        id: "organization_available_authorizations_#{authorization_workflow.name}_allow_ephemeral_participation",
+                        checked: f.object.available_authorizations&.dig(authorization_workflow.name, "allow_ephemeral_participation") == true,
+                        disabled: !authorization_workflow.ephemerable,
+                        class: ("hide" if !authorization_workflow.ephemerable)
+                      } # options
+                    ) %>
+              </td>
+            </tr>
+          <% end %>
+      <% end %>
+    </tbody>
+  </table>
+</div>
+
+<script>
+  $(document).ready(function () {
+    var $allowEphemeralParticipationInputs = $('input[id^="organization_available_authorizations_"][id$="_allow_ephemeral_participation"]')
+    
+    $allowEphemeralParticipationInputs.on('change',function(){
+      $allowEphemeralParticipationInputs.each(function(){
+        $(this).prop('checked', false);
+      });
+      $(this).prop('checked', true);
+    });
+  });
+</script>
diff --git a/decidim-ephemeral_participation/app/views/decidim/system/organizations/edit.html.erb b/decidim-ephemeral_participation/app/views/decidim/system/organizations/edit.html.erb
new file mode 100644
index 0000000000..0063d25239
--- /dev/null
+++ b/decidim-ephemeral_participation/app/views/decidim/system/organizations/edit.html.erb
@@ -0,0 +1,36 @@
+<%= decidim_form_for(@form) do |f| %>
+  <div class="field">
+    <%= f.text_field :name, autofocus: true %>
+  </div>
+
+  <div class="field">
+    <%= f.text_field :host %>
+  </div>
+
+  <div class="field">
+    <%= f.text_area :secondary_hosts %>
+    <p class="help-text"><%= I18n.t("decidim.system.organizations.edit.secondary_hosts_hint") %></p>
+  </div>
+
+  <div class="field">
+    <%= f.label :force_authentication %>
+    <%= f.check_box :force_users_to_authenticate_before_access_organization %>
+  </div>
+
+  <div class="field">
+    <%= f.label :users_registration_mode %>
+    <%= f.collection_radio_buttons :users_registration_mode,
+                                   Decidim::Organization.users_registration_modes,
+                                   :first,
+                                   ->(mode) { I18n.t("decidim.system.organizations.users_registration_mode.#{mode.first}") } %>
+  </div>
+
+  <%= render partial: "authorizations_settings", locals: { f: f } %>
+  <%= render partial: "smtp_settings", locals: { f: f } %>
+  <%= render partial: "omniauth_settings", locals: { f: f } %>
+  <%= render partial: "file_upload_settings", locals: { f: f } %>
+
+  <div class="actions">
+    <%= f.submit I18n.t("decidim.system.actions.save") %>
+  </div>
+<% end %>
diff --git a/decidim-ephemeral_participation/app/views/decidim/system/organizations/new.html.erb b/decidim-ephemeral_participation/app/views/decidim/system/organizations/new.html.erb
new file mode 100644
index 0000000000..dbc2ca2dde
--- /dev/null
+++ b/decidim-ephemeral_participation/app/views/decidim/system/organizations/new.html.erb
@@ -0,0 +1,77 @@
+<% provide :title do %>
+  <h2><%= t ".title" %></h2>
+<% end %>
+
+<%= decidim_form_for(@form) do |f| %>
+  <div class="field">
+    <%= f.text_field :name, autofocus: true %>
+  </div>
+
+  <div class="field">
+    <%= f.text_field :reference_prefix %>
+    <p class="help-text"><%= I18n.t("decidim.system.organizations.new.reference_prefix_hint") %></p>
+  </div>
+
+  <div class="field">
+    <%= f.text_field :host %>
+  </div>
+
+  <div class="field">
+    <%= f.text_area :secondary_hosts %>
+    <p class="help-text"><%= I18n.t("decidim.system.organizations.new.secondary_hosts_hint") %></p>
+  </div>
+
+  <div class="field">
+    <%= f.text_field :organization_admin_name %>
+  </div>
+
+  <div class="field">
+    <%= f.email_field :organization_admin_email %>
+  </div>
+
+  <%= f.fields_for :locales do |fields| %>
+    <div class="field">
+      <%= f.label :organization_locales, "", class: @form.respond_to?(:errors) && @form.errors[:default_locale].present? ? "is-invalid-label" : "" %>
+      <table>
+        <thead>
+          <tr>
+            <td>Locale</td>
+            <td>Enabled <%= f.error_for(:available_locales) %></td>
+            <td>Default? <%= f.error_for(:default_locale) %></td>
+          </tr>
+        </thead>
+        <tbody>
+          <% localized_locales.each do |locale| %>
+            <tr>
+              <td><%= locale.name %></td>
+              <td><%= check_box_tag "organization[available_locales][#{locale.id}]", locale.id, @form.available_locales.include?(locale.id) %></td>
+              <td><%= radio_button_tag "organization[default_locale]", locale.id, @form.default_locale == locale.id %></td>
+            </tr>
+          <% end %>
+        </tbody>
+      </table>
+    </div>
+  <% end %>
+
+  <div class="field">
+    <%= f.label :force_authentication %>
+    <%= f.check_box :force_users_to_authenticate_before_access_organization %>
+  </div>
+
+  <div class="field">
+    <%= f.label :users_registration_mode %>
+    <%= f.collection_radio_buttons :users_registration_mode,
+                                   Decidim::Organization.users_registration_modes,
+                                   :first,
+                                   ->(mode) { I18n.t("decidim.system.organizations.users_registration_mode.#{mode.first}") } %>
+  </div>
+
+  <%= render partial: "authorizations_settings", locals: { f: f } %>
+  <%= render partial: "smtp_settings", locals: { f: f } %>
+  <%= render partial: "omniauth_settings", locals: { f: f } %>
+  <%= render partial: "file_upload_settings", locals: { f: f } %>
+
+  <div class="actions">
+    <%= f.submit I18n.t("decidim.system.models.organization.actions.save_and_invite") %>
+  </div>
+<% end %>
diff --git a/decidim-ephemeral_participation/app/views/layouts/decidim/_user_menu.html.erb b/decidim-ephemeral_participation/app/views/layouts/decidim/_user_menu.html.erb
new file mode 100644
index 0000000000..c3e645e2a2
--- /dev/null
+++ b/decidim-ephemeral_participation/app/views/layouts/decidim/_user_menu.html.erb
@@ -0,0 +1,24 @@
+<% if current_user.ephemeral_participant? %>
+  <%= render partial: "layouts/decidim/ephemeral_participation/user_menu" %>
+<% else %>
+
+  <%# The code BELOW raises: Cannot use t(".profile") shortcut because path is not available %>
+  <%# 
+    decidim_gem_dir = Gem::Specification.find_by_name("decidim").gem_dir
+    view_path = "decidim-core/app/views/layouts/decidim/_user_menu.html.erb"
+    decidim_core_user_menu_partial = "#{decidim_gem_dir}/#{view_path}"
+  %>
+  <%#= render file: decidim_core_user_menu_partial %>
+  <%# The code ABOVE raises: Cannot use t(".profile") shortcut because path is not available %>
+
+  <li><%= link_to I18n.t("profile", scope: "layouts.decidim.user_menu"), decidim.account_path, tabindex: "-1" %></li>
+  <% if current_user.nickname.present? && !current_user.managed? %>
+    <li><%= link_to I18n.t("public_profile", scope: "layouts.decidim.user_menu"), decidim.profile_path(current_user.nickname), tabindex: "-1" %></li>
+  <% end %>
+  <li><%= link_to I18n.t("notifications", scope: "layouts.decidim.user_menu"), decidim.notifications_path, tabindex: "-1" %></li>
+  <li><%= link_to I18n.t("conversations", scope: "layouts.decidim.user_menu"), decidim.conversations_path, tabindex: "-1" %></li>
+  <% if allowed_to? :read, :admin_dashboard %>
+    <li><%= link_to I18n.t("admin_dashboard", scope: "layouts.decidim.user_menu"), decidim_admin.root_path, tabindex: "-1" %></li>
+  <% end %>
+  <li><%= link_to I18n.t("sign_out", scope: "layouts.decidim.user_menu"), decidim.destroy_user_session_path, method: :delete, class: "sign-out-link", tabindex: "-1" %></li>
+<% end %>
diff --git a/decidim-ephemeral_participation/app/views/layouts/decidim/ephemeral_participation/_user_menu.html.erb b/decidim-ephemeral_participation/app/views/layouts/decidim/ephemeral_participation/_user_menu.html.erb
new file mode 100644
index 0000000000..43c7fe2852
--- /dev/null
+++ b/decidim-ephemeral_participation/app/views/layouts/decidim/ephemeral_participation/_user_menu.html.erb
@@ -0,0 +1,40 @@
+<li>
+  <%=
+    t(
+      "remaining",
+      scope: "decidim.ephemeral_participation.user_menu",
+      remaining: (
+        Decidim::EphemeralParticipation::SessionPresenter
+        .new(current_user, self)
+        .ephemeral_participant_session_remaining_time_in_minutes
+      )
+    )
+  %>
+</li>
+<% if current_user.verifiable_ephemeral_participant? %>
+  <li>
+    <%=
+      link_to(
+        I18n.t("complete_registration", scope: "decidim.ephemeral_participation.user_menu"),
+        decidim_ephemeral_participation.edit_ephemeral_participant_path(current_user),
+        tabindex: "-1",
+      )
+    %>
+  </li>
+<% end %>
+<li>
+  <%=
+    link_to(
+      I18n.t("sign_out", scope: "decidim.ephemeral_participation.user_menu"),
+      decidim_ephemeral_participation.ephemeral_participant_path(current_user, redirect_url: request.path), 
+      method: :delete,
+      class: "sign-out-link",
+      tabindex: "-1"
+    )
+  %>
+</li>
+
+<%#
+  Maybe use JS to style dropdown and draw attention to it.
+  Also: would be nice to have a live countdown for the session.
+%>
diff --git a/decidim-ephemeral_participation/app/views/layouts/decidim/ephemeral_participation/user_profile.html.erb b/decidim-ephemeral_participation/app/views/layouts/decidim/ephemeral_participation/user_profile.html.erb
new file mode 100644
index 0000000000..a3065c15e4
--- /dev/null
+++ b/decidim-ephemeral_participation/app/views/layouts/decidim/ephemeral_participation/user_profile.html.erb
@@ -0,0 +1,31 @@
+<%= render "layouts/decidim/application" do %>
+  <div class="wrapper">
+    <div class="row collapse">
+      <div class="columns">
+        <h1 class="heading1 user-header">
+          <%= I18n.t("title", scope: "decidim.ephemeral_participation.ephemeral_participants") %>
+        </h1>
+      </div>
+    </div>
+    <div class="row collapse">
+      <div class="main-container">
+        <div class="row collapse main-container--side-panel">
+          <div class="columns medium-4 large-3">
+            <div class="side-panel">
+              <ul class="tabs vertical side-panel__tabs" id="user-settings-tabs">
+                <%#= user_menu.render %>
+              </ul>
+            </div>
+          </div>
+          <div class="columns medium-8 large-9">
+            <div class="main-container__content">
+              <div class="tabs-content vertical" aria-hidden="false">
+                <%= yield %>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+<% end %>
diff --git a/decidim-ephemeral_participation/config/locales/ca.yml b/decidim-ephemeral_participation/config/locales/ca.yml
new file mode 100644
index 0000000000..4e7ce351dc
--- /dev/null
+++ b/decidim-ephemeral_participation/config/locales/ca.yml
@@ -0,0 +1,51 @@
+---
+ca:
+  activemodel:
+    attributes:
+      organization:
+        enabled: Actiu
+        allows_ephemeral_participation: Permet participació sense registre
+    errors:
+      models:
+        organization:
+          attributes:
+            available_authorizations:
+              invalid: Only one authorization method can be used to allow ephemeral participation
+        permission:
+          attributes:
+            base:
+              invalid_ephemeral_participation_permissions: Cannot set permissions using multiple authorizations when '%{ephemeral_participation_authorization}' authorization is selected and '%{ephemeral_participation_enabled}' component setting is enabled.
+        settings:
+          attributes:
+            ephemeral_participation_enabled:
+              missing_ephemeral_participation_authorization: Must enable ephemeral participation authorization at system level.
+  decidim:
+    authorization_handlers:
+      ephemerable: Permet participació directe
+    ephemeral_participation:
+      actions:
+        unauthorized: "No tens permís per realitzar aquesta acció: %{link}"
+        unauthorized_link: Completa el teu registre aquí.
+        unverified: "Per poder participar, cal que estiguis verificada: %{link}"
+        unverified_link: Completa el procés de verificació aquí.
+        verified: "Completa el teu registre %{link}"
+        verified_link: aquí.
+      login_modal:
+        button: Vull participar sense registrar-me
+        help: Fes servir aquesta opció per una participació puntual
+      user_menu:
+        remaining: "%{remaining} min. per la desconexió automàtica"
+        sign_out: Cancel·la i desconnecta
+        complete_registration: Completa el teu registre
+      ephemeral_participants:
+        create: Per poder participar sense registre, has de completar el procés de verificació
+        destroy: S'ha cancel·lat la participació sense registre
+        submit: Envia
+        title: Completa el teu perfil d'usuari per simplificar la teva participació en el futur
+        unverifiable: No ha estat possible completar la verificació. Pots tornar a intentar-ho en un altre moment.
+    components:
+      budgets:
+        settings:
+          global:
+            ephemeral_participation_enabled: Ephemeral participation enabled
+            ephemeral_participation_enabled_help: Allows users to participate without registration. Requires configuring permissions.
diff --git a/decidim-ephemeral_participation/config/locales/en.yml b/decidim-ephemeral_participation/config/locales/en.yml
new file mode 100644
index 0000000000..6b195b5f7f
--- /dev/null
+++ b/decidim-ephemeral_participation/config/locales/en.yml
@@ -0,0 +1,51 @@
+---
+en:
+  activemodel:
+    attributes:
+      organization:
+        enabled: Enabled
+        allows_ephemeral_participation: Allows participation without registering
+    errors:
+      models:
+        permission:
+          attributes:
+            base:
+              invalid_ephemeral_participation_permissions: Cannot set permissions using multiple authorizations when '%{ephemeral_participation_authorization}' authorization is selected and '%{ephemeral_participation_enabled}' component setting is enabled.
+        organization:
+          attributes:
+            available_authorizations:
+              invalid: Only one authorization method can be used to allow ephemeral participation
+        settings:
+          attributes:
+            ephemeral_participation_enabled:
+              missing_ephemeral_participation_authorization: Must enable ephemeral participation authorization at system level.
+  decidim:
+    authorization_handlers:
+      ephemerable: Allows direct participation
+    ephemeral_participation:
+      actions:
+        unauthorized: "You are not authorized to perform this action: %{link}"
+        unauthorized_link: Finish your registration here.
+        unverified: "You need to be verified in order tor participate: %{link}"
+        unverified_link: Complete the verification process here.
+        verified: "Finish your registration %{link}"
+        verified_link: here.
+      login_modal:
+        button: I want to participate without registering
+        help: Use this option for a one-time participation
+      user_menu:
+        remaining: "%{remaining} min. before automatic sign out"
+        sign_out: Cancel and sign out
+        complete_registration: Finish your registration
+      ephemeral_participants:
+        create: en.decidim.ephemeral_participation.ephemeral_participants.create
+        destroy: en.decidim.ephemeral_participation.ephemeral_participants.destroy
+        submit: Send
+        title: Complete your user profile for easily future participation
+        unverifiable: The verification process has been unsuccessful. You can try it again later.
+    components:
+      budgets:
+        settings:
+          global:
+            ephemeral_participation_enabled: Ephemeral participation enabled
+            ephemeral_participation_enabled_help: Allows users to participate without registration. Requires configuring permissions.
diff --git a/decidim-ephemeral_participation/config/locales/es.yml b/decidim-ephemeral_participation/config/locales/es.yml
new file mode 100644
index 0000000000..f8bb50be2f
--- /dev/null
+++ b/decidim-ephemeral_participation/config/locales/es.yml
@@ -0,0 +1,51 @@
+---
+es:
+  activemodel:
+    attributes:
+      organization:
+        enabled: Activo
+        allows_ephemeral_participation: Permite la participación sin registro
+    errors:
+      models:
+        permission:
+          attributes:
+            base:
+              invalid_ephemeral_participation_permissions: Cannot set permissions using multiple authorizations when '%{ephemeral_participation_authorization}' authorization is selected and '%{ephemeral_participation_enabled}' component setting is enabled.
+        organization:
+          attributes:
+            available_authorizations:
+              invalid: Only one authorization method can be used to allow ephemeral participation
+        settings:
+          attributes:
+            ephemeral_participation_enabled:
+              missing_ephemeral_participation_authorization: Must enable ephemeral participation authorization at system level.
+  decidim:
+    authorization_handlers:
+      ephemerable: Permite participación directa
+    ephemeral_participation:
+      actions:
+        unauthorized: "No tienes permisos para realizar esta acción: %{link}"
+        unauthorized_link: Completa tu registro aquí.
+        unverified: "Para poder participar, es necesario que estés verificada: %{link}"
+        unverified_link: Completa el proceos de verificación aquí.
+        verified: "Completa tu registro %{link}"
+        verified_link: aquí.
+      login_modal:
+        button: Quiero participar sin registrarme
+        help: Utiliza esta opción para una participación puntual
+      user_menu:
+        remaining: "%{remaining} min. para desconexión automática"
+        sign_out: Cancela y desconecta
+        complete_registration: Completa tu registro
+      ephemeral_participants:
+        create: es.decidim.ephemeral_participation.ephemeral_participants.create
+        destroy: Se ha cancelado la participación sin registro
+        submit: Enviar
+        title: Completa tu perfil de usuario para simplificar tu participación en el futuro
+        unverifiable: unverifiable es
+    components:
+      budgets:
+        settings:
+          global:
+            ephemeral_participation_enabled: Ephemeral participation enabled
+            ephemeral_participation_enabled_help: Allows users to participate without registration. Requires configuring permissions.
diff --git a/decidim-ephemeral_participation/db/migrate/20210518192857_update_organizations_available_authorizations.rb b/decidim-ephemeral_participation/db/migrate/20210518192857_update_organizations_available_authorizations.rb
new file mode 100644
index 0000000000..fc7801089a
--- /dev/null
+++ b/decidim-ephemeral_participation/db/migrate/20210518192857_update_organizations_available_authorizations.rb
@@ -0,0 +1,38 @@
+class UpdateOrganizationsAvailableAuthorizations < ActiveRecord::Migration[5.2]
+  class Organization < ApplicationRecord
+    self.table_name = :decidim_organizations
+  end
+
+  def up
+    workflows = {}
+    
+    Organization.find_each do |organization|
+      workflows[organization.id] =
+        organization.available_authorizations.each_with_object({}) do |workflow, hash|
+          hash[workflow] = { allow_ephemeral_participation: false }
+        end
+    end
+
+    remove_column :decidim_organizations, :available_authorizations
+    add_column    :decidim_organizations, :available_authorizations, :jsonb, default: {}
+
+    Organization.find_each do |organization|
+      organization.update!(available_authorizations: workflows[organization.id])
+    end
+  end
+
+  def down
+    workflows = {}
+    
+    Organization.find_each do |organization|
+      workflows[organization.id] = organization.available_authorizations.keys
+    end
+
+    remove_column :decidim_organizations, :available_authorizations
+    add_column    :decidim_organizations, :available_authorizations, :string, array: true, default: []
+
+    Organization.find_each do |organization|
+      organization.update!(available_authorizations: workflows[organization.id])
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/decidim-ephemeral_participation.gemspec b/decidim-ephemeral_participation/decidim-ephemeral_participation.gemspec
new file mode 100644
index 0000000000..86f578dd48
--- /dev/null
+++ b/decidim-ephemeral_participation/decidim-ephemeral_participation.gemspec
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+$LOAD_PATH.push File.expand_path("../lib", __FILE__)
+
+# Describe your gem and declare its dependencies:
+Gem::Specification.new do |s|
+  s.name        = "decidim-ephemeral_participation"
+  s.summary     = "A decidim module that allows users to participate without registration."
+  s.description = s.summary
+  s.version     = "0.0.1"
+  s.authors     = ["Ivan Vergés"]
+  s.email       = ["ivan@platoniq.net"]
+
+  s.files = Dir["{app,config,db,lib}/**/*", "Rakefile", "README.md"]
+
+  s.add_dependency "decidim-verifications"
+
+  s.add_development_dependency "decidim-dev"
+end
diff --git a/decidim-ephemeral_participation/lib/decidim/ephemeral_participation.rb b/decidim-ephemeral_participation/lib/decidim/ephemeral_participation.rb
new file mode 100644
index 0000000000..4a0bb4b2a9
--- /dev/null
+++ b/decidim-ephemeral_participation/lib/decidim/ephemeral_participation.rb
@@ -0,0 +1,7 @@
+require "decidim/ephemeral_participation/engine"
+require "decidim/ephemeral_participation/verifications_workflow_manifest_override"
+
+module Decidim
+  module EphemeralParticipation
+  end
+end
diff --git a/decidim-ephemeral_participation/lib/decidim/ephemeral_participation/engine.rb b/decidim-ephemeral_participation/lib/decidim/ephemeral_participation/engine.rb
new file mode 100644
index 0000000000..c26599c6f5
--- /dev/null
+++ b/decidim-ephemeral_participation/lib/decidim/ephemeral_participation/engine.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    class Engine < ::Rails::Engine
+      isolate_namespace Decidim::EphemeralParticipation
+
+      config.to_prepare do
+        # commands
+        Decidim::Admin::TransferUser.include(Decidim::EphemeralParticipation::TransferUserOverride)
+        # controllers
+        Decidim::ApplicationController.include(Decidim::EphemeralParticipation::ApplicationControllerOverride)
+        Decidim::Admin::ConflictsController.include(Decidim::EphemeralParticipation::ConflictsControllerOverride)
+        # forms
+        Decidim::Admin::ComponentForm.include(Decidim::EphemeralParticipation::ComponentFormOverride)
+        Decidim::Admin::PermissionsForm.include(Decidim::EphemeralParticipation::PermissionsFormOverride)
+        Decidim::Admin::TransferUserForm.include(Decidim::EphemeralParticipation::TransferUserFormOverride)
+        Decidim::System::UpdateOrganizationForm.include(Decidim::EphemeralParticipation::UpdateOrganizationFormOverride)
+        # models
+        Decidim::Component.include(Decidim::EphemeralParticipation::ComponentOverride)
+        Decidim::Organization.include(Decidim::EphemeralParticipation::OrganizationOverride)
+        Decidim::PermissionAction.include(Decidim::EphemeralParticipation::PermissionActionOverride)
+        Decidim::User.include(Decidim::EphemeralParticipation::UserOverride)
+        # permissions
+        Decidim::Permissions.include(Decidim::EphemeralParticipation::PermissionsOverride)
+        # budgets states
+        Decidim::Budgets::ProjectListItemCell.include(Decidim::EphemeralParticipation::ProjectListItemCellOverride)
+
+      end
+
+      initializer "ephemeral_participation.component_override" do
+        Decidim.component_registry.find(:budgets).tap do |component|
+          component.settings(:global) do |settings|
+            settings.attribute(:ephemeral_participation_enabled, type: :boolean, default: false)
+          end
+        end
+      end
+
+      routes do
+        scope :ephemeral_participation do
+          resources :ephemeral_participants, only: [:create, :edit, :update, :destroy]
+        end
+      end
+    end
+  end
+end
diff --git a/decidim-ephemeral_participation/lib/decidim/ephemeral_participation/verifications_workflow_manifest_override.rb b/decidim-ephemeral_participation/lib/decidim/ephemeral_participation/verifications_workflow_manifest_override.rb
new file mode 100644
index 0000000000..dc9b6e2599
--- /dev/null
+++ b/decidim-ephemeral_participation/lib/decidim/ephemeral_participation/verifications_workflow_manifest_override.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Decidim
+  module EphemeralParticipation
+    module VerificationsWorkflowManifestOverride
+      extend ActiveSupport::Concern
+
+      included do
+        # Allows to be configured (in /system) for ephermeral participation (where available)
+        attribute :ephemerable, Virtus::Attribute::Boolean, default: false
+
+        def description
+          ephemerable_text = ", #{I18n.t("ephemerable", scope: "decidim.authorization_handlers")}" if ephemerable
+          "#{fullname} (#{I18n.t(type, scope: "decidim.authorization_handlers")}#{ephemerable_text})"
+        end
+      end
+    end
+  end
+end
+
+# needs to be available in initializers
+Decidim::Verifications::WorkflowManifest.include(Decidim::EphemeralParticipation::VerificationsWorkflowManifestOverride)
diff --git a/decidim-valid_auth/app/controllers/decidim/valid_auth/authorizations_controller.rb b/decidim-valid_auth/app/controllers/decidim/valid_auth/authorizations_controller.rb
index b9be835dea..c0078cd7ae 100644
--- a/decidim-valid_auth/app/controllers/decidim/valid_auth/authorizations_controller.rb
+++ b/decidim-valid_auth/app/controllers/decidim/valid_auth/authorizations_controller.rb
@@ -43,4 +43,4 @@ def load_authorization
       end
     end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/budgets_workflow_pam2020.rb b/lib/budgets_workflow_pam2020.rb
index 216e880b2d..d9b5f0d25a 100644
--- a/lib/budgets_workflow_pam2020.rb
+++ b/lib/budgets_workflow_pam2020.rb
@@ -52,8 +52,8 @@ def user_authorization
   def user_scope_resource
     return unless user_authorization_scope
 
-    @user_scope_resource ||= budgets.each do |resource|
-      return resource if resource.scope == user_authorization_scope
+    @user_scope_resource ||= budgets.find do |resource|
+      resource.scope == user_authorization_scope
     end
   end
 
diff --git a/lib/budgets_workflow_pam2021.rb b/lib/budgets_workflow_pam2021.rb
new file mode 100644
index 0000000000..209c6ae28c
--- /dev/null
+++ b/lib/budgets_workflow_pam2021.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+# Specific Workflow for Barcelona's 2021 PAM
+class BudgetsWorkflowPam2021 < Decidim::Budgets::Workflows::Base
+  PAM2021AUTHORIZATIONHANDLER = 'census_sms_authorization_handler'
+
+  # The budget resource in the user's scope is highlighted.
+  def highlighted?(resource)
+    return unless user_scope_resource && !voted?(user_scope_resource)
+
+    resource == user_scope_resource
+  end
+
+  # Can vote in the budget resource in the user's scope
+  # and in an extra budget resource out of its scope
+  def vote_allowed?(resource, consider_progress = true)
+    return true if resource == user_scope_resource
+
+    resources_with_order = voted
+    resources_with_order += progress if consider_progress
+
+    (resources_with_order - [user_scope_resource, resource]).empty?
+  end
+
+  # The user can change of mind and change the vote on these budget resources
+  #
+  # Returns Array.
+  def discardable
+    (voted + progress) - [user_scope_resource]
+  end
+
+  # The user can vote on maximum 2 budget resources
+  #
+  # Returns Boolean.
+  def limit_reached?
+    (voted + progress).count < 3
+  end
+
+  private
+
+  # Returns Object (Authorization).
+  def user_authorization
+    @user_authorization ||= Decidim::Authorization.find_by(
+      name: PAM2021AUTHORIZATIONHANDLER,
+      user: user
+    )
+  end
+
+  # The budget resources the user can and should vote on
+  #
+  # Returns Object (Decidim::Budgets:Budget).
+  def user_scope_resource
+    return unless user_authorization_scope
+
+    @user_scope_resource ||= budgets.find do |resource|
+      resource.scope == user_authorization_scope
+    end
+  end
+
+  # The user's scope from the verifcation
+  #
+  # Returns Object (Scope).
+  def user_authorization_scope
+    return unless user_authorization
+
+    @user_authorization_scope ||= Decidim::Scope.find_by(
+      "name->>'ca' = '#{user_authorization.metadata['scope']}'"
+    )
+  end
+end
diff --git a/spec/system/census16_authorization_spec.rb b/spec/system/census16_authorization_spec.rb
index e0641ebca5..99359acf8f 100644
--- a/spec/system/census16_authorization_spec.rb
+++ b/spec/system/census16_authorization_spec.rb
@@ -13,7 +13,7 @@
     )
   end
 
-  let(:authorizations) { ["census16_authorization_handler"] }
+  let(:authorizations) { {"census16_authorization_handler" => {"allow_ephemeral_participation" => true}} }
   let!(:scope) { create :scope, organization: organization, code: "1" }
 
   let(:response) do
diff --git a/spec/system/census_authorization_spec.rb b/spec/system/census_authorization_spec.rb
index e102102e19..329e2d441f 100644
--- a/spec/system/census_authorization_spec.rb
+++ b/spec/system/census_authorization_spec.rb
@@ -13,7 +13,7 @@
     )
   end
 
-  let(:authorizations) { ["census_authorization_handler"] }
+  let(:authorizations) { {"census_authorization_handler" => {"allow_ephemeral_participation" => true}} }
   let!(:scope) { create :scope, organization: organization, code: "1" }
 
   let(:response) do
diff --git a/spec/system/census_sms_authorization_spec.rb b/spec/system/census_sms_authorization_spec.rb
new file mode 100644
index 0000000000..2e316a9f05
--- /dev/null
+++ b/spec/system/census_sms_authorization_spec.rb
@@ -0,0 +1,141 @@
+# frozen_string_literal: true
+
+require "rails_helper"
+
+describe "Census + SMS authorization", type: :system, perform_enqueued: true, with_authorization_workflows: ["census_sms_authorization_handler"] do
+  let(:organization) do
+    create(
+      :organization,
+      name: "Ajuntament",
+      default_locale: :ca,
+      available_locales: [:es, :ca],
+      available_authorizations: authorizations
+    )
+  end
+
+  let(:authorization_name) { "El padró + SMS" }
+  let(:authorizations) { {"census_sms_authorization_handler" => {"allow_ephemeral_participation" => true}} }
+  let(:code) { user_authorization.verification_metadata["verification_code"] }
+  let(:user_authorization) { Decidim::Authorization.find_by(user: user, name: "census_sms_authorization_handler") }
+
+  let!(:scope) { create :scope, organization: organization, code: "1" }
+
+  let(:response) do
+    Nokogiri::XML("<codiRetorn>01</codiRetorn>").remove_namespaces!
+  end
+
+  # Selects a birth date that will not cause errors in the form: January 12, 1979.
+  def fill_in_authorization_form
+    select "DNI", from: "authorization_document_type"
+    fill_in "authorization_document_number", with: "12345678A"
+    select "12", from: "authorization_date_of_birth_3i"
+    select "Gener", from: "authorization_date_of_birth_2i"
+    select "1979", from: "authorization_date_of_birth_1i"
+    fill_in "authorization_postal_code", with: "08001"
+    fill_in "authorization_mobile_phone_number", with: "(+34) 654 321 987"
+    check "authorization_tos_acceptance"
+    select translated(scope.name), from: "authorization_scope_id"
+  end
+
+  before do
+    allow_any_instance_of(Decidim::CensusSms::Verification::AuthorizationForm).to receive(:response).and_return(response)
+    switch_to_host(organization.host)
+  end
+
+  context "when visiting authorizations" do
+    let(:user) { create(:user, :confirmed, organization: organization) }
+
+    before do
+      login_as user, scope: :user
+      visit decidim.root_path
+    end
+
+    it "allows the user to authorize against available authorizations" do
+      within_user_menu do
+        click_link "El meu compte"
+      end
+
+      click_link "Autoritzacions"
+      click_link authorization_name
+
+      fill_in_authorization_form
+      click_button "Verifica't"
+
+      expect(page).to have_content("Has completat el primer pas")
+
+      fill_in "confirmation_verification_code", with: code
+      click_button "Verifica't"
+
+      expect(page).to have_content("T'has verificat correctament")
+
+      visit decidim_verifications.authorizations_path
+
+      within ".authorizations-list" do
+        expect(page).to have_content(authorization_name)
+        expect(page).not_to have_link(authorization_name)
+      end
+    end
+
+    it "allows the user to reset the verification code" do
+      within_user_menu do
+        click_link "El meu compte"
+      end
+
+      click_link "Autoritzacions"
+      click_link authorization_name
+
+      fill_in_authorization_form
+      click_button "Verifica't"
+
+      click_link "Restableix el codi de verificació"
+
+      fill_in "reset[mobile_phone_number]", with: "(+34) 654 321 987"
+      click_button "Envia'm un nou codi"
+
+      expect(page).to have_content("T'hem enviat un nou codi de verificació")
+
+      fill_in "confirmation_verification_code", with: code
+      click_button "Verifica't"
+
+      expect(page).to have_content("T'has verificat correctament")
+
+      visit decidim_verifications.authorizations_path
+
+      within ".authorizations-list" do
+        expect(page).to have_content(authorization_name)
+        expect(page).not_to have_link(authorization_name)
+      end
+    end
+
+    context "when the user has completed the first authorization step" do
+      let!(:code) { "012345" }
+      let!(:authorization) { create(:authorization, :pending, name: "census_sms_authorization_handler", user: user, verification_metadata: { verification_code: code, code_sent_at: Time.current }) }
+
+      it "can resume the authorization" do
+        visit decidim_verifications.authorizations_path
+
+        click_link authorization_name
+
+        expect(page).to have_content("Introdueix el codi")
+
+        fill_in "confirmation_verification_code", with: code
+        click_button "Verifica't"
+
+        expect(page).to have_content("T'has verificat correctament")
+      end
+    end
+
+    context "when the user has already been authorised" do
+      let!(:authorization) { create(:authorization, name: "census_sms_authorization_handler", user: user) }
+
+      it "shows the authorization at their account" do
+        visit decidim_verifications.authorizations_path
+
+        within ".authorizations-list" do
+          expect(page).to have_content(authorization_name)
+          expect(page).to have_content(I18n.localize(authorization.granted_at, format: :long, locale: :ca))
+        end
+      end
+    end
+  end
+end