<!--
SPDX-FileCopyrightText: 2022 Alembic Pty Ltd
SPDX-License-Identifier: MIT
-->
# Upgrading
## Upgrading to version 5.0.0
Version 5.0.0 includes several breaking changes related to action types and the Google OAuth strategy. Most changes can be handled automatically using the upgrade task.
### Dependencies
This version requires Assent ~> 0.3.0 (updated from ~> 0.2.9) and adds `nimble_totp` as a dependency for the new TOTP strategy. Run `mix deps.get` after updating your `ash_authentication` version.
### Automated Upgrade
If you have [Igniter](https://hexdocs.pm/igniter) installed, run:
```bash
mix ash_authentication.upgrade 4.x.x 5.0.0
```
Replace `4.x.x` with your current version. This will automatically:
- Convert token resource `revoked?` actions from `:read` to `:action` type
- Convert password reset and magic link request actions from `:read` to `:action` type
- Create `get_by_<identity_field>` read actions where needed
- Update `"google_hd"` references to `"hd"` in your codebase
### Breaking Changes
#### 1. Sender failures now propagate as errors
Previously, sender failures were silently ignored. Now, senders that return `{:error, reason}` will cause the authentication action to fail with an `AshAuthentication.Errors.SenderFailed` error.
**What this affects:**
- Password reset requests
- Magic link requests
- Confirmation emails
**Action required:** Review your sender implementations. If they can return `{:error, reason}`, ensure your application handles these failures appropriately. Senders returning `:ok` or `{:ok, result}` (common with mailer libraries) will continue to work unchanged.
**Recommended approach:** Consider using a durable background job library like [Oban](https://hexdocs.pm/oban) for sending authentication emails. This provides automatic retries, failure tracking, and prevents transient email delivery issues from blocking user authentication flows. Your sender can enqueue a job and return `:ok` immediately, while the actual email delivery happens asynchronously with built-in resilience.
```elixir
defmodule MyApp.AuthEmailSender do
use AshAuthentication.Sender
def send(user_or_email, token, opts) do
%{user_or_email: user_or_email, token: token, opts: opts}
|> MyApp.Workers.AuthEmail.new()
|> Oban.insert()
:ok
end
end
```
#### 2. Request actions converted to generic actions
Password reset request (`request_password_reset_with_password`) and magic link request (`request_magic_link`) actions are now generated as `:action` type instead of `:read`.
**Action required:** If you have customised these actions as `:read` actions, the upgrader will convert them automatically. If you've made extensive customisations, review the converted code to ensure it still meets your requirements.
The new actions work with auto-generated `get_by_<identity_field>` read actions for user lookup.
#### 3. Token revoked action converted to generic action
The `revoked?` action on token resources is now a generic action returning a boolean, rather than a read action returning a record.
**Action required:** If you have a custom `revoked?` read action on your token resource, the upgrader will convert it automatically.
#### 4. Google strategy now uses OIDC
The Google OAuth strategy now uses OIDC (via Assent 0.3.0) instead of the legacy API. This changes two fields in the `user_info` map:
| Old | New |
|-----|-----|
| `user_info["google_hd"]` | `user_info["hd"]` |
| `user_info["email_verified"]` (string `"true"`) | `user_info["email_verified"]` (boolean `true`) |
**Action required:**
1. The upgrader will automatically rename `"google_hd"` to `"hd"` in your code
2. You must manually update any checks for `email_verified`:
```elixir
# Before
user_info["email_verified"] == "true"
# After
user_info["email_verified"] == true
```
### New Features
#### TOTP Two-Factor Authentication
Version 5.0.0 adds a complete TOTP (Time-based One-Time Password) strategy for two-factor authentication. See the [TOTP tutorial](/documentation/tutorials/totp.md) for setup instructions.
#### Extra JWT Claims
You can now add custom claims to JWT tokens using the `extra_claims` option in the tokens DSL section, or dynamically via `AshAuthentication.add_token_claims/2`. See the [tokens guide](/documentation/topics/tokens.md) for details.
### Other Improvements
- **Auto signout in AshAuthentication.Phoenix** - Automatic sign-out is now supported in the Phoenix integration
- **API key header prefix regex support** - The `ApiKey.Plug` now accepts regex patterns for header prefix matching
- **Better error handling** - `Jwt.token_for_user/2` now returns `{:error, AuthenticationFailed.t}` on failure instead of raising
## Upgrading to version 4.0.0
Version 4.0.0 of AshAuthentication adds support for Ash 3.0 and in line with [a number of changes in Ash](`e:ash:upgrading-to-3.0.html`) there are some corresponding changes to Ash Authentication:
- Token generation is enabled by default, meaning that you will have to explicitly set [`authentication.tokens.enabled?`](documentation/dsls/DSL-AshAuthentication.md#authentication-tokens-enabled?) to `false` if you don't need them.
- Sign in tokens are enabled by default in the password strategy. What this means is that instead of returning a regular user token on sign-in in the user's metadata, we generate a short-lived token which can be used to actually sign the user in. This is specifically to allow live-view based sign-in UIs to display an authentication error without requiring a page-load.
## Upgrading to version 3.6.0.
As of version 3.6.0 the `TokenResource` extension adds the `subject` attribute
which allows us to more easily match tokens to specific users. This unlocks
some new use-cases (eg sign out everywhere).
This means that you will need to generate new migrations and migrate your
database.
### Upgrade steps:
> ### Warning {: .warning}
>
> If you already have tokens stored in your database then the migration will
> likely throw a migration error due to the new `NOT NULL` constraint on
> `subject`. If this happens then you can either delete all your tokens or
> explicitly add the `subject` attribute to your resource with `allow_nil?` set
> to `true`. eg:
>
> ```elixir
> attributes do
> attribute :subject, :string, allow_nil?: true
> end
> ```
1. Run `mix ash_postgres.generate_migrations --name=add_subject_to_token_resource`
2. Run `mix ash_postgres.migrate`
3. 🎉