Auth0을 사용하여 NestJS 애플리케이션 보호

TL;DR: 본 논문에서는 NestJS 기반 API를 보호하는 방법Auth0을 설명합니다.또한 현재 로그인한 사용자 프로필을 수신하기 위한 Auth0 관리 API도 포함됩니다.
만약 네가 이 글을 읽고 싶지 않다면, 너는 직접 가도 된다GitHub repository.
지난주에 Auth0을 NestJS 프로젝트에 연결하려고 노력했습니다.
API의 일부 노드 공개를 제한하고 싶습니다.
사용자 데이터와 암호를 자신의 서버에 저장하고 싶지 않기 때문에 Auth0을 사용하기로 했습니다.
한동안 백엔드 응용 프로그램의 프레임워크로 NestJS를 사용해 왔습니다.NestJS를 사용하면 새 사용자가 쉽게 시작할 수 있습니다.
이것은 데이터베이스 연결, 검증, 로그 기록, http 요청 등 필요에 따라 프로젝트에 통합할 수 있는 많은 유용한 기능을 제공하는 성숙한 CLI를 제공합니다.
나는 절망해서 효과적인 해결 방법을 찾지 못했다.트위터와 dev.to에서 도움을 요청합니다.

아이템 더 이상 사용 불가


액체 오류: 내부
나는 그곳에서 매우 유용한 건의를 받았다는 직접적인 메시지를 받았다.
불행히도 나는 그것을 일하게 할 수 없어서 며칠 쉬고 생각을 멈추기로 결정했다.
이것은 매우 좋은 생각이다. 결국 나는 이 문제를 해결했다🥳.

Auth0 구성


만약 Auth0 계정이 없다면, 그들의 sign up 페이지로 돌아가서 하나를 만들어야 합니다.
Auth0은 암호가 없는 사용자 계정, 두 개의 소셜 신분 제공 업체(예를 들어 구글, 페이스북, 트위터, GitHub)와 그에 대한 지원을 제공하는 아낌없는 무료 층을 제공한다.
본 강좌와 비교적 작은 보조 프로젝트에 대해서는 무료 계획이 충분할 것이다.

커뮤니티 API 생성


대시보드에 로그인한 후 API 섹션으로 이동하여create API 버튼을 클릭하여 새 API를 만듭니다.

그런 다음 API 이름과 식별자를 입력하라는 메시지가 표시됩니다.
Auth0은 URL을 식별자와 API의 친근한 이름으로 사용하는 것을 권장합니다.
서명 알고리즘은 기본 옵션(RS256)을 유지해야 합니다.

응용 프로그램 만들기


Auth0은 새 응용 프로그램을 만들 때 유형을 입력해야 합니다.
이 예에서 유형은 중요하지 않다.사용 가능한 응용 프로그램을 공개하려면 에 대한 더 많은 정보를 읽어서 용도에 맞는 유형을 선택해야 할 수도 있습니다.
application types


응용 프로그램을 만든 후 허용된 콜백 URL을 구성해야 합니다.리셋 URL은 인증이 성공적으로 수행된 후 사용자가 리디렉션할 수 있는 위치입니다.

Auth0 관리 API 활성화


인증된 사용자의 프로필을 나중에 읽고 싶으므로 방금 만든 응용 프로그램에 Auth0 관리 API를 활성화해야 합니다.
Auth0 관리 API를 활성화하는 구성은 API 탭에서 확인할 수 있습니다.
또한 읽기: 사용자 범위를 선택해야 합니다.

로그인


나중에 API를 사용할 수 있도록 액세스 토큰을 생성해야 합니다.토큰은 Auth0 로그인 양식을 통해 생성됩니다.
로그인 양식은 Auth0에서 제공하며 Auth0 임대 도메인에서 액세스할 수 있습니다.
Auth0 클라이언트 id가 필요합니다. 이 두 값은 프로그램 설정 페이지에서 복사할 수 있습니다.

URL의 값을 대체하고 브라우저에서 엽니다.https://$AUTH0_DOMAIN/authorize?audience=http://localhost:3000&scope=SCOPE&response_type=code&client_id=$AUTH0_CLIENT_ID&redirect_uri=http://localhost:4200/login&state=STATE?prompt=none
SSO 공급업체에 로그인하거나 이메일과 비밀번호를 사용한 후.
그리고 로그인 폼은 으로 다시 지정됩니다. 이것은 우리가 이전에 설정한 것입니다.
웹 응용 프로그램이 실행되지 않는 것은 상관없지만, 파라미터의 값을 복사해서 나중에 사용할 수 있도록 저장해야 합니다.
적재 영패를 생성하려면 code 이 필요합니다.
http://localhost:4200/login

사용자 메타데이터 업데이트


Auth0의 장점 중 하나는 사용자 프로필에 메타데이터를 첨부할 수 있다는 것입니다.
사용자 메타데이터를 사용하여 사용자 프로필을 다른 서비스(예를 들어 GitHub나 dev.to profile)에 연결할 수 있습니다. 다른 많은 용례를 발견할 수 있을 거라고 믿습니다.


새 NestJS 응용 프로그램 만들기


$ npm i -g @nestjs/cli
$ nest new nestjs-auth0-jwt
문제가 해결되면 다음 디렉토리 구조를 가진 새 NestJS 응용 프로그램이 생성됩니다.
nestjs-auth0-jwt
├── src
│   ├── app.controller.spec.ts
│   ├── app.controller.ts
│   ├── app.module.ts
│   ├── app.service.ts
│   └── main.ts
├── test
│   ├── app.e2e-spec.ts
│   └── jest-e2e.json
├── README.md
├── nest-cli.json
├── package-lock.json
├── package.json
├── tsconfig.build.json
├── tsconfig.json
└── tslint.json

응용 프로그램 실행


새 디렉토리로 이동하여 API를 시작합니다.
$ cd nestjs-auth0-jwt
$ npm run start:dev
응용 프로그램이 실행되면 브라우저를 열고 에 들어갈 수 있습니다.
http://localhost:3000

의존 항목 추가


$ npm install --save @nestjs/passport passport passport-jwt jwks-rsa auth0
$ npm install --save-dev @types/passport-jwt @types/auth0

인증 모듈 만들기


$ nest generate module auth

JWT 전략 작성


$ touch auth/jwt.strategy.ts
import { passportJwtSecret } from 'jwks-rsa';
import { ExtractJwt, Strategy, VerifiedCallback } from 'passport-jwt';

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      secretOrKeyProvider: passportJwtSecret({
        cache: true,
        rateLimit: true,
        jwksRequestsPerMinute: 5,
        jwksUri: `https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`
      }),

      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), // 1
      audience: 'http://localhost:3000',
      issuer: `https://${process.env.AUTH0_DOMAIN}/`
    });
  }

  validate(payload: any, done: VerifiedCallback) {
    if (!payload) {
      done(new UnauthorizedException(), false); // 2
    }

    return done(null, payload);
  }
}
1:code: 새 추출기를 만듭니다. 이 추출기 사용 방안인'bearer'가 권한 수여 헤더에서 JSON 웹 영패를 찾습니다.
2: 유효 부하를 받지 못하면 검증에 실패합니다.

AuthModule 업데이트


import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';

import { JwtStrategy } from './jwt.strategy';

@Module({
  imports: [PassportModule],
  providers: [JwtStrategy],
  exports: [JwtStrategy]
})
export class AuthModule {}

API 끝 만들기


import { ManagementClient, User } from 'auth0';
import * as express from 'express';

import { Controller, Get, Request, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello(); // 1
  }

  @Get('secret')
  @UseGuards(AuthGuard('jwt')) // 2
  secretEndpoint(@Request() req: express.Request): string {
    return 'this endpoint should be protected';
  }

  @Get('profile')
  @UseGuards(AuthGuard('jwt')) // 2
  async profile(@Request() req: express.Request): Promise<any> {
    const authZero = new ManagementClient({
      // 3
      domain: process.env.AUTH0_DOMAIN,
      clientId: process.env.AUTH0_CLIENT_ID,
      clientSecret: process.env.AUTH0_CLIENT_SECRET,
      scope: 'read:users update:users'
    });

    const response = await authZero
      .getUser({ id: req.user.sub }) // 4
      .then((user: User) => {
        return user;
      })
      .catch(err => {
        return err;
      });

    return response;
  }
}
1: 공용 API 종료점입니다.
2: ExtractJwt.fromAuthHeaderAsBearerToken()3: Auth0 관리 API 클라이언트를 만듭니다.
4: JWT 응답의 테마는 Auth0 사용자 ID와 같습니다. 따라서, @UseGuards(AuthGuard('jwt')) 속성은 sub 호출된 id 매개 변수로 사용되며, 이 호출은 전체 사용자 프로필을 되돌려줍니다.

로그인 코드로 불러오는 영패 검색


$ export AUTH0_DOMAIN=${AUTH0_DOMAIN}
$ export AUTH0_CLIENT_ID=${AUTH0_CLIENT_ID}
$ export AUTH0_CLIENT_SECRET=${AUTH0_CLIENT_SECRET}
$ export CODE=${CODE}

$ curl -X POST -H 'content-type: application/json' -d '{
  "grant_type": "authorization_code",
  "client_id": "'$AUTH0_CLIENT_ID'",
  "client_secret": "'$AUTH0_CLIENT_SECRET'",
  "code": "'$CODE'",
  "redirect_uri": "http://localhost:4200"
}' https://$AUTH0_DOMAIN/oauth/token
{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik9EQXpOMEZHTWpBd1FVUTJORFpETXpBMVJETXdSRUUyTjBSRE5qRXpNemRFUWtNMk5URTFNUSJ9.eyJpc3MiOiJodHRwczovL25lc3Rqcy1hdXRoMC1qd3QuYXUuYXV0aDAuY29tLyIsInN1YiI6Imdvb2dsZS1vYXV0aDJ8MTEzMDc2NzYwNTUyNTQ5MTY1ODQ5IiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwIiwiaWF0IjoxNTY1OTg1MzU3LCJleHAiOjE1NjYwNzE3NTcsImF6cCI6IjR0eFZVSm5ZVlRhbzRsczA2dFozRGNCdm5JVk9uY01RIn0.U3dVcaFPY5ZHlz9sntx3O2Svz_HfapBpryrUB9ipIdoIHgu_Skp40FGaLu0Fx-_Uo2GE4pfvM-XR1bQgQGyVbMhALpe2CZrKKCe9k1v4VZ_zxwhYDdV8WNr99jmbMtnm_I9rZIz3YU9dyjWlV_ktHV0bPHj1wIjBUrUc9P_EF5Vw3CeNMxlFXZ2xYldT9XdYUotJHIoJ-e_KWo0hMn_qF5xvWxD-RJIQL7G2ZxEcsmMe9JovwZoAnoqaIyutMP8g7X1UfoTGs-Fa6B1xXhtrYBms--sm_FrM5w0rjIyOuyujulPTeXO8_CbuL1Yz5kCcBsuJdXTiyTcTV9R8W0f4Rg",
  "expires_in": 86400,
  "token_type": "Bearer"
}

응용 프로그램 실행


변수 getUser, ${AUTH0_DOMAIN}${AUTH0_CLIENT_ID} 를 이전에 저장한 값으로 대체한 다음 NestJS 응용 프로그램을 시작합니다.
$ export AUTH0_DOMAIN=${AUTH0_DOMAIN}
$ export AUTH0_CLIENT_ID=${AUTH0_CLIENT_ID}
$ export AUTH0_CLIENT_SECRET=${AUTH0_CLIENT_SECRET}
$ npm run start:dev

인증 없이 요청


응용 프로그램이 실행되면 cURL을 사용하여 API 끝점${AUTH0_CLIENT_SECRET}/secret에 액세스합니다.
두 노드 모두 /profile 주석 태그를 사용했기 때문에 공개적으로 사용할 수 없는 401 (권한 없음) 오류가 발생합니다.
$ curl http://localhost:3000/secret
$ curl http://localhost:3000/profile

인증 요청


현재 같은 요청을 실행할 수 있지만 AuthGuard 헤더를 통해 접근 영패를 제공합니다.
이전에 권한을 부여받았기 때문에 현재 두 개의 개인 단점 Authorization/secret 을 처리할 수 있습니다./profile 엔드포인트는 Auth0에서 구성 파일 정보로 돌아옵니다. Auth0 관리 API에서 이러한 정보를 받았습니다.
Auth0 관리 API는 JWT 응답의 (테마) 필드를 사용하여 사용자 프로필을 검색합니다.
예제 응용 프로그램의 JWT 응답은 문서 상의 이유로 콘솔에 기록됩니다.
$ curl http://localhost:3000/secret \
  -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik9EQXpOMEZHTWpBd1FVUTJORFpETXpBMVJETXdSRUUyTjBSRE5qRXpNemRFUWtNMk5URTFNUSJ9.eyJpc3MiOiJodHRwczovL25lc3Rqcy1hdXRoMC1qd3QuYXUuYXV0aDAuY29tLyIsInN1YiI6Imdvb2dsZS1vYXV0aDJ8MTEzMDc2NzYwNTUyNTQ5MTY1ODQ5IiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwIiwiaWF0IjoxNTY1OTg1MzU3LCJleHAiOjE1NjYwNzE3NTcsImF6cCI6IjR0eFZVSm5ZVlRhbzRsczA2dFozRGNCdm5JVk9uY01RIn0.U3dVcaFPY5ZHlz9sntx3O2Svz_HfapBpryrUB9ipIdoIHgu_Skp40FGaLu0Fx-_Uo2GE4pfvM-XR1bQgQGyVbMhALpe2CZrKKCe9k1v4VZ_zxwhYDdV8WNr99jmbMtnm_I9rZIz3YU9dyjWlV_ktHV0bPHj1wIjBUrUc9P_EF5Vw3CeNMxlFXZ2xYldT9XdYUotJHIoJ-e_KWo0hMn_qF5xvWxD-RJIQL7G2ZxEcsmMe9JovwZoAnoqaIyutMP8g7X1UfoTGs-Fa6B1xXhtrYBms--sm_FrM5w0rjIyOuyujulPTeXO8_CbuL1Yz5kCcBsuJdXTiyTcTV9R8W0f4Rg'
$ curl http://localhost:3000/profile \
  -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik9EQXpOMEZHTWpBd1FVUTJORFpETXpBMVJETXdSRUUyTjBSRE5qRXpNemRFUWtNMk5URTFNUSJ9.eyJpc3MiOiJodHRwczovL25lc3Rqcy1hdXRoMC1qd3QuYXUuYXV0aDAuY29tLyIsInN1YiI6Imdvb2dsZS1vYXV0aDJ8MTEzMDc2NzYwNTUyNTQ5MTY1ODQ5IiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwIiwiaWF0IjoxNTY1OTg1MzU3LCJleHAiOjE1NjYwNzE3NTcsImF6cCI6IjR0eFZVSm5ZVlRhbzRsczA2dFozRGNCdm5JVk9uY01RIn0.U3dVcaFPY5ZHlz9sntx3O2Svz_HfapBpryrUB9ipIdoIHgu_Skp40FGaLu0Fx-_Uo2GE4pfvM-XR1bQgQGyVbMhALpe2CZrKKCe9k1v4VZ_zxwhYDdV8WNr99jmbMtnm_I9rZIz3YU9dyjWlV_ktHV0bPHj1wIjBUrUc9P_EF5Vw3CeNMxlFXZ2xYldT9XdYUotJHIoJ-e_KWo0hMn_qF5xvWxD-RJIQL7G2ZxEcsmMe9JovwZoAnoqaIyutMP8g7X1UfoTGs-Fa6B1xXhtrYBms--sm_FrM5w0rjIyOuyujulPTeXO8_CbuL1Yz5kCcBsuJdXTiyTcTV9R8W0f4Rg'
이 문서에서는 NestJS 응용 프로그램에서 Auth0 같은 인증 제공 프로그램을 실현하는 방법을 알려드릴 수 있기를 바랍니다.
Auth0과 인증을 내 프로젝트에 통합하는 것은 나에게 매우 번거롭지만, 결국 나는 그것을 일하게 하여 매우 좋다고 느낀다.

마티아스🧔
@fullstack\u

🥳 나 드디어 성공했어!이제 나는 Auth0으로 API 노드를 보호할 수 있다. 나는 또 다른 노드를 보호할 수 있다. 그 중에서 JWT 영패 소유자의 개요 파일은 Auth0에서 얻은 것이다👏나는 내가 그것을 어떻게 완성했는지에 대해 몇 줄을 쓸 것이다.📝
18:2019년 8월 15일 오후 25시

마티아스🧔
@fullstack\u

이 순간들은 내가 왜 인코딩을 좋아하는지 일깨워 주었다❤️다시 한 번 말하지만, 때로는 사물을 재검토하기 위해 특정한 문제를 한동안 처리하지 않는 것이 일리가 있다.
18:2019년 8월 15일 오후 27시
dev.to


NestJS 프로젝트에서 Auth0 인증을 사용할 수 없습니다.나는 아직도 이곳에서 도움을 찾고 있다.
Matthias 🤖

나는 이 문제에 대해 며칠 동안 발버둥을 친 후에 하루 정도 쉬었고 나의 코드를 건드리지 않았다.
나는 깨끗한 머리로 다시 시작해서 한 시간 안에 문제를 해결할 수 있다🥳.
이것이 바로 내가 프로그래밍을 좋아하는 이유이다. 네가 성과를 거둘 때, 너는 항상 이런 위대한 순간을 가지고 있다💪
통상적으로 몇 시간이나 며칠마다 작은 돌파구가 있다.나에게 있어서, 이것은 내가 일하는 중에 가장 사람을 격려하는 일이다.
겸사겸사 한마디: 나는 이 문제를 어떻게 해결하는지에 관한 문장을 쓰고 있다😉.
나는 또한 에 있는 NestJS 문서를 개선하여 사람들이 그것을 더욱 쉽게 정확하게 실현하고 안전 빈틈을 피할 수 있다고 생각한다.그러나 나는 NestJS가 개원된 것이라 불평하지 않는다. 모든 사람이 Authentication 문서를 얻을 수 있다.
NestJS, Auth0 또는 기타 주제에 대해 궁금한 점이 있으면 주저 없이 DM 한 통을 쓰거나 메일을 보내주십시오improve.나는 너를 도와 매우 기쁘다!

[email protected] 링크

  • NestJS documentation
  • Auth0
  • 만약 네가 나의 내용을 좋아한다면, 너는 아마 트위터에서 나를 주목하고 싶을 것이다?!
    표지 이미지는 Auth0 Management API documentation 에서

    좋은 웹페이지 즐겨찾기