TESLA FleetAPIのOAuthをVercel+独自ドメインでモバイルアプリに対応する構成メモ

## はじめに
Tesla FleetAPIを使ってモバイルアプリと連携しようとした際、 OAuth2.0 のリダイレクトURIが壁となったので備忘録としてメモします。

TeslaのOAuthサーバーは安全性の観点から、一般的なカスタムURLスキーム「myapp://...」をリダイレクトURIに認めてくれません。

この記事では、Vercel + 独自ドメインを使うことで、**NS(ネームサーバー)を譲渡することなく** TESLA OAuth のリダイレクトを自分のアプリに簡単に戻す構成をまとめます。

## そもそも何をやりたかったのか？
FleetAPIが公開される前から開発をしていたアプリ（といっても指定時間にAPIを叩く簡易なもの）がありました。その際はサードパーティの認証アプリを使ってトークンを得るのが嫌だったため、アプリ側でテスラのブランクページをリダイレクトURIとして挟み、レスポンスからトークンの獲得をしていました（非公式APIだったので）
FleetAPIが公開されたことで、さすがに公式で公開されたのであればそちらで開発し直そうとなりました。前回同様クライアント側で全て処理したかった（もといサーバーを立てるのが面倒だった）のですが、中継サーバーが必要となったため下記のようなフローを考えました。

```
TESLA OAuth →
https://auth.example.com/callback
↓（実際の処理は Cloudflare Workers に委任）
Cloudflare Workers が myapp://auth にリダイレクト
↓
アプリに戻る
```
ここで問題が発生します。CloudFlare Workersを用いると、固定のIPアドレスは存在しない＆直接IPを割り当てることはできない。Cloudflare Workersはグローバルなエッジネットワーク上で動作していて、複数のIPアドレスからレスポンスを返す仕組み（Anycast）になっています。今回は所属企業のサブドメインを用いるため無論ドメインを移管することはできません。

```
ざっくり
1. モバイルアプリでTesla FleetAPIを使いたい
2. OAuth認証フローが必要
3. 認証が終わったら → myapp://auth?code=... にトークンを戻したい
4. でもFleetAPIの仕様としてmyapp://を認めていない
5. しかも .vercel.app や .web.app も認められていない
6. CloudFlare Workersと独自ドメインで動かそうと思ったけどNSを渡したくない
```
**じゃあ普通に auth.example.com の A を設定する感じでだめなのか？**
Cloudflare Workersをカスタムドメインで動かすためには、「Cloudflare の Workers Routing 機能」を使って、Cloudflare のエッジ上でリクエストを捕まえて Workers に流す必要があり、CloudflareがDNSのオーソリティである必要があります。
```
auth.example.com → Aレコードで自社サーバーのIPやCloudflareのIPに向ける
↓
でもCloudflareはそのリクエストを Workers に割り当てない
↓
→ Workers は反応しない
```
整理してみると

|方法|特徴|問題点|
|---|---|---|
|NSをCloudflareに移管|Workersが一番スムーズに動く|NS明け渡しが社内的にNGの場合がある
|IP指定やAレコードだけで対応|社内NSのまま維持可能|Cloudflare Workersにルーティングできない|
|CNAMEでWorkersに向ける|一見使えそうに見える|CloudflareはCNAMEルーティング非対応（Workersには）|
|Cloudflare Tunnel + 自前サーバー|NS維持したままEdgeで処理可能|設定や維持が重くなる|

一番下はCloudflare Edge→Tunnel→社内→Workersと今回の目的にはかなりオーバーです。
なんせこれだけの処理のためなので
```
GET /callback?code=abc123 → HTTP 302 → myapp://auth?code=abc123
```
だったら怠けずにサーバーを立てろよって話ですが...

## 結果どうしたか
ここで社内サーバーを管理しているエンジニアさんに相談をしました。
回答としては
「普通にworkerやりたいだけなら自分で立ち上げられるジョブキュー(GearmandやTheSchwartz)でよいのでは...」と
「**移管はドラスティックな上、Cloudflareが1.1.1.1持ってる時点で、NS取る気満々やん**」と...

回答を元に再度整理すると
|構成|メリット|デメリット|
|---|---|---|
|Cloudflare Workers（NS渡す）|スピード・保守性・拡張性|主権移譲・透明性の低下|
|自前サーバー + ジョブキュー|制御自由・独立性高|初期構成とメンテが必要|
|Workers + 自前API or Redis Queue|	クラウドの恩恵 + ロジック独立	|ハイブリッド設計がやや複雑|
- NS渡して→代償は理解しておく。
- 主権や透明性を保ちたいなら、自前のリダイレクト＋ジョブキュー構成
- ハイブリッド構成でWAFとしての恩恵だけもらいつつ、処理は自前で


それでも私は立てるのが面倒だったので
FirebaseHosting+Functions・Verce・Netlify・Lambdaと調べていった結果
「CNAME連携+Vercel Functionsで中継」という構成となりました。

## 実際の作業
やっと実際の作業の話になります。

①　サーバレス関数の作成
```api/callback.ts
import type { VercelRequest, VercelResponse } from '@vercel/node';

export default function handler(req: VercelRequest, res: VercelResponse) {
  const { code, state } = req.query;

  if (!code || typeof code !== 'string') {
    res.status(400).send('Missing or invalid code');
    return;
  }

  const redirectUrl = `myapp://auth?code=${encodeURIComponent(code)}${
    state && typeof state === 'string' ? `&state=${encodeURIComponent(state)}` : ''
  }`;

  res.writeHead(302, { Location: redirectUrl });
  res.end();
}
```
```vercel.json
{
  "version": 2,
  "routes": [
    { "src": "/api/callback", "dest": "/api/callback.ts" }
  ]
}
```
② Vercel に独自ドメインをCNAMEでつなぐ
- DNS側（レジストラなど）で設定
```
タイプ:   CNAME
名前:     auth
値:       cname.vercel-dns.com.
```
③ TESLA FleetAPIにリダイレクトURIを登録

|項目|値|
|---|---|
| AllowedRedirect URI | https://auth.example.com/api/callback |
| Allowed Origin(s) | https://auth.tesla.com または空欄|

はいとっても簡単です。

## まとめ

ざっくり
- TESLA OAuthは`myapp://`も無料のサブドメインも対応していない
- VercelのFunctionsが思ったより薄くて使いやすい
- ドメイン管理の主権について学びが多くありました