auth0関連
用語整理
テナント:プロジェクト的な感じ
dev/staging/productionで環境のタグもある
アプリ
API
データベース
バックエンドPHP関連
<?php
namespace App\Service/Auth0Service;
use Auth0\SDK\API\Authentication;
use Auth0\SDK\API\Management;
use Auth0\SDK\Auth0;
final class Auth0Service
{
private function management(): Management
{
$auth = $this->authentication();
$res = $auth->client_credentials([
'client_id' => env('AUTH0_MANAGEMENT_CLIENT_ID'),
'client_secret' => env('AUTH0_MANAGEMENT_CLIENT_SECRET'),
'audience' => env('AUTH0_MANAGEMENT_API_END_POINT'),
'grant_type' => 'client_credentials',
]);
return new Management(
$res['access_token'],
env('AUTH0_DOMAIN')
);
}
private function authentication(): Authentication
{
return new Authentication(
env('AUTH0_DOMAIN'),
env('AUTH0_CLIENT_ID'),
env('AUTH0_CLIENT_SECRET')
);
}
private function auth0(): Auth0
{
return new Auth0([
'domain' => env('AUTH0_DOMAIN'),
'client_id' => env('AUTH0_CLIENT_ID'),
'client_secret' => env('AUTH0_CLIENT_SECRET'),
'redirect_uri' => 'http://localhost:3001/test/user',
]);
}
フロント関連
@auth0/auth0-spa-js
と auth0-js
の違い
@auth0/auth0-spa-js
の方が新しくて、ユニバーサルログインが必須になる
auth0-js
古いけど既存のログインのUI変更したくないなど、ユニバーサルログインを使いたくない場合は使わざるを得ない
また、SDKの併用は可能(auth0-js
でログインするけど、token関連の処理は新しい@auth0/auth0-spa-js
を使って、トークンを取得するなど
ログイン必須のエラーだけ握りつぶしている書き方好ましくないが、現状公式もこの書き方なので、好ましい書き方が不明。
isAuthenticated
というメソッドがあるが、リロードすると毎回falseを返す(getTokenSilentlyをすると、trueを返すが)ので、ログイン済みかの判定に使えない
import { Auth0Client } from '@auth0/auth0-spa-js'
import { auth0ClientId, auth0Domain, auth0RedirectUrl } from '@/config'
import { pagesPath } from '@/utils/$path'
const domain: string = auth0Domain
const redirect_uri: string = auth0RedirectUrl
const auth0App = new Auth0Client({
client_id: auth0ClientId,
redirect_uri,
domain,
useRefreshTokens: true,
})
export const auth0Login = async () => {
await auth0App.loginWithPopup({
redirect_uri,
})
}
export const getToken = async () => {
try {
const token = await auth0App.getTokenSilently()
return token
} catch (e: any) {
if (e && typeof e === 'object' && e?.error !== 'login_required') {
throw e
}
return null
}
}
export const auth0logout = async () => {
await auth0App.logout({
returnTo: pagesPath.login.$url().pathname,
})
}
ユーザー情報の移行
この方法で簡単に移行できそう
twitterとの連携
spa利用してるときにtokenが401で取れない
デフォルトのアプリを使っていて、SPA用のモードになっていない
Terraform関連
2年前から正式対応しているらしいので、安定してそう
バックエンドnodejs
googleログインで必要最低限片付けしたものが Auth0User
なので、多少の違いはログイン方法でありそう。
clientSecret
はなくても動く
import { AuthenticationClient } from 'auth0'
import { auth0ClientId, auth0ClientSecret, auth0Domain } from '@/config'
const auth0 = new AuthenticationClient({
domain: auth0Domain,
clientId: auth0ClientId,
clientSecret: auth0ClientSecret,
})
export interface Auth0User {
sub: string
email: string
name: string
}
export const verifyToken = async (token: string): Promise<Auth0User> => {
const profile = await auth0.getProfile(token)
return profile as Auth0User
}
// if (process.env.NODE_ENV === 'test') {
// describe('verifyToken', () => {
// it('トークンの検証', async () => {
// const res = await verifyToken(
// '',
// )
// console.log({ res })
// })
// })
// }
firabase authとの比較
やれることが多いからか、めちゃくちゃ使いにくい
シンプルなSPA用のトークンの自前のAPIサーバーとやり取りをしたいだけなのに、その前に必要なことがめちゃくちゃ多い
認証だけでいいなら、firebaseで良さそう?
@TODO: 認可関連
@TODO: organization関連
golang api
import (
"context"
"strings"
"github.com/auth0/go-auth0/authentication"
"github.com/morikuni/failure"
)
type Auth0User struct {
Name string `json:"name"`
Email string `json:"email"`
Sub string `json:"sub"`
}
func decodeAth0Token(ctx context.Context, token string) (*Auth0User, error) {
domain := "local-iesapuri-poc.jp.auth0.com"
clientID := "C8gxrMxKAd9dNe0noQuQkDovLdcg1qRY"
clientSecret := "evRz4UeQt8e4gCsa-uO5pbg78N_SoyPvStaibv4AQE0UvMNiJck7GXfFR54RWTEb"
authAPI, err := authentication.New(
ctx,
domain,
authentication.WithClientID(clientID),
authentication.WithClientSecret(clientSecret), // Optional depending on the grants used
)
if err != nil {
return nil, failure.Wrap(err)
}
user, err := authAPI.UserInfo(ctx, token)
if err != nil {
return nil, failure.Wrap(err)
}
sub := splitSub(user.Sub)
u := &Auth0User{
Name: user.Name,
Email: user.Email,
Sub: sub,
}
return u, nil
}
func splitSub(sub string) string {
arr1 := strings.Split(sub, "|")
return arr1[1]
}
ユーザー側から新規登録を不可にする