背景
- 社内システムを使うのにアカウントの管理が面倒だった
- ちょうどOktaを使い始める風潮があったので相乗りしたかった
前提
- Oktaを導入している
やること
- Oktaのアプリを登録する
- フロントエンドでOktaのSSOを実装する
- バックエンドでアクセストークンの検証をする
参考
- フロントエンド (Next.js)
- バックエンド (NestJS)
実装の一部
フロントエンド
// pages/api/auth/[...nextauth].ts import NextAuth from 'next-auth'; import provider from 'next-auth/providers'; export default NextAuth({ providers: [ provider.Okta({ clientId: process.env.OKTA_CLIENTID, clientSecret: process.env.OKTA_CLIENTSECRET, domain: process.env.OKTA_DOMAIN, }), ], theme: 'auto', });
アプリを登録した際に発行されるClient ID/Client Secretを渡してあげる。
DomainはHTTPスキーマを抜いた形式 (xxx.okta.com/oauth2/$issuer
)
pages/api/auth/[...nextauth].ts
のパスはnext-authの指定。
NextAuth.jsに処理を以上するためには/api/auth/*の形式である必要がある。
バックエンド
基本的には参考したURLのものそのままだが、やることは以下
- passport jsの実装
- guardsの実装
Passport Strategyをまず実装する。
// auth/http.strategy.ts import { HttpException, Injectable } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { Strategy } from 'passport-http-bearer'; import { AuthService } from './auth.service'; @Injectable() export class HttpStrategy extends PassportStrategy(Strategy) { constructor(private readonly service: AuthService) { super(); } async validate( token: string, done: (error: HttpException, value: boolean | string) => any, ) { try { return await this.service.validateToken(token); } catch (error) { done(error, 'token is invalid'); } } }
AuthService内で実際の検証作業を実施する。 validateはAuthGuardによって呼ばれており、User等を返すとそのままリクエストに付与してくれる。
ガードしたいエンドポイントにデコレータで宣言すれば終わり。
// user.controller.ts @Get() @UseGuards(AuthGuard('bearer')) async getUsers(): Promise<User[]> { return this.service.getUsers(); }