devise_token_authで複数認証するとアクセストークンが返ってこなかった

Railsでdevise_token_authを使ってAPIの認証機能を作っているときに、User以外のモデル(例えばAdminなど)を追加したらレスポンスヘッダーにアクセストークン等がなくてハマった話。

## 環境

- rails (5.2.1)
- [devise_token_auth](https://github.com/lynndylanhurley/devise_token_auth) (0.2.0)
- [active_model_serializers](https://github.com/rails-api/active_model_serializers/tree/0-10-stable) (0.10.8)

## 最初の認証モデルを作成

まず最初にactive_model_serializersをインストールして使える状態にした。
続いて、devise_token_authをインストールしてUserモデルを作成した。

```bash
$ rails g devise_token_auth:install User user
$ rails db:migrate
```

```rb:config/routes.rb
mount_devise_token_auth_for 'User', at: 'user'
```

だいだいこんな感じでUserモデルの認証機能ができるので、適当にUserを作成してアクセストークンを取得してみる。

```rb
User.create!(email: "hoge@hoge.com", password: "password")
```

```bash
$ curl -D - -X "POST" "http://localhost:3000/user/sign_in" -H "Content-Type: application/json" -d $'{"email": "hoge@hoge.com", "password": "password"}'

HTTP/1.1 200 OK
X-Frame-Options: xxxxxxxxxxxxxxxxxx
X-XSS-Protection: xxxxxxxxxxxxxxxxxx
X-Content-Type-Options: xxxxxxxxxxxxxxxxxx
X-Download-Options: xxxxxxxxxxxxxxxxxx
X-Permitted-Cross-Domain-Policies: xxxxxxxxxxxxxxxxxx
Referrer-Policy: xxxxxxxxxxxxxxxxxx
Content-Type: application/json; charset=utf-8
access-token: xxxxxxxxxxxxxxxxxx
token-type: xxxxxxxxxxxxxxxxxx
client: xxxxxxxxxxxxxxxxxxx
expiry: xxxxxxxx
uid: hoge@hoge.com
Vary: xxxxxxxxxxxxxxxxxx
ETag: xxxxxxxxxxxxxxxxxx
Cache-Control: xxxxxxxxxxxxxxxxxx
X-Request-Id: xxxxxxxxxxxxxxxxxx
X-Runtime: xxxxxxxxxxxxxxxxxx
Transfer-Encoding: xxxxxxxxxxxxxxxxxx
```

ログインが成功して作成したUserの`access-token`、`token-type`、`client`、`expiry`、`uid`をレスポンスヘッダーに含まれるので、以降はこれらをリクエストヘッダーに入れてアクセスする感じ。

## 続いて管理者用のモデルを追加してみる

devise_token_authは複数の認証モデルもサポートしているので、新しく管理者用のモデルとしてAdminモデルを追加みてみる。

```bash
$ rails g devise_token_auth:install Admin admin
$ rails db:migrate
```

```rb:config/routes.rb
mount_devise_token_auth_for 'User', at: 'user'
mount_devise_token_auth_for 'Admin', at: 'admin'
```

だいだいこんな感じでAdminモデルの認証機能ができるので、適当にAdminを作成してアクセストークンを取得してみる。

```rb
Admin.create!(email: "admin@hoge.com", password: "password")
```

```bash
$ curl -D - -X "POST" "http://localhost:3000/admin/sign_in" -H "Content-Type: application/json" -d $'{"email": "admin@hoge.com", "password": "password"}'

HTTP/1.1 200 OK
X-Frame-Options: xxxxxxxxxxxxxxxxxx
X-XSS-Protection: xxxxxxxxxxxxxxxxxx
X-Content-Type-Options: xxxxxxxxxxxxxxxxxx
X-Download-Options: xxxxxxxxxxxxxxxxxx
X-Permitted-Cross-Domain-Policies: xxxxxxxxxxxxxxxxxx
Referrer-Policy: xxxxxxxxxxxxxxxxxx
Content-Type: application/json; charset=utf-8
Vary: xxxxxxxxxxxxxxxxxx
ETag: xxxxxxxxxxxxxxxxxx
Cache-Control: xxxxxxxxxxxxxxxxxx
X-Request-Id: xxxxxxxxxxxxxxxxxx
X-Runtime: xxxxxxxxxxxxxxxxxx
Transfer-Encoding: xxxxxxxxxxxxxxxxxx
```

なんてこった、`access-token`、`token-type`、`client`、`expiry`、`uid`がない。
さっきのUserではあったのに、いったい何故・・・

## 解決策

[stackoverflow](https://stackoverflow.com/questions/41011398/work-around-for-issue-multiple-user-models-with-devise-token-auth-and-active-mod)に同じような事例があった。
どうもactive_model_serializerの影響っぽい。
ソースコードあんまり読んでないけど、[ここ](https://github.com/rails-api/active_model_serializers/blob/0-10-stable/lib/action_controller/serialization.rb#L20)で指定しているscopeがcurrent_userになってるから？

とりあえず回答にあるように、devise_token_authのSessionsControllerをoverrideしたらちゃんとアクセストークンが返ってきた。

```rb:app/controllers/admin/sessions_controller.rb
def render_create_success
  render json: {
    data: resource_data(resource_json: @resource.token_validation_response)
  }, scope: :current_admin
end
```

active_model_serializerが影響してるとは思わなかったのでハマってしまったが、もっと良い解決策がないかもう少し調査が必要かも・・・

---

## 追記

overrideするよりapplication_controllerに以下を追加する方法のほうが良さそう。

```rb:application_controller.rb
serialization_scope :view_context
```