• SDK
  • OIDC

간단한 클라이언트 측 OIDC SDK 구현하기

Logto는 다양한 플랫폼을 위한 다양한 SDK를 제공합니다. 공식 SDK 외에도, 우리는 커뮤니티의 개발자들이 자신들만의 사용자 친화적인 SDK를 만드는 것을 장려합니다. 이 글은 OIDC를 위한 기본 클라이언트 측 SDK를 만드는 방법에 대해 안내할 것입니다.

Simeng
Simeng
Developer

소개

Logto는 개발자와 비즈니스 그룹에게 광범위한 고객 신원 및 접근 관리 (CIAM) 솔루션을 제공합니다. 우리는 다양한 플랫폼과 응용 프로그램 프레임워크를 위한 준비완료된 SDK를 다양하게 제공하고 있습니다. 우리의 Logto 클라우드 서비스와 함께, 당신은 몇 분 안에 애플리케이션을 위한 매우 안전한 사용자 인증 흐름을 매우 쉽게 구축할 수 있습니다. 개발자 커뮤니티에서 탄생한 회사인 Logto는 커뮤니티 참여를 받아들이고 중요시합니다. Logto가 공식적으로 개발한 SDK를 보완하고, 우리는 지속적으로 다양하고 사용자 친화적인 SDK를 만들어 다양한 플랫폼과 프레임워크의 독특한 요구사항을 충족시키는 방법으로 커뮤니티에서 개발자들의 전문성을 기여하도록 장려하고 열렬히 환영합니다. 이 글에서는, 우리는 어떻게 OIDC 표준 auth SDK를 단계별로 구현하는지 간략히 보여줄 것입니다.

배경

OpenID Connect (OIDC) 플로우는 OAuth 2.0 프레임워크를 바탕으로 한 인증 프로토콜로, 신원 검증과 단일 사인온 기능을 제공합니다. 이를 통해 사용자는 애플리케이션과 함께 인증을 진행하고 안전하게 모든 개인 자원에 대한 추가적인 접근 권한을 얻을 수 있습니다. OIDC 규격을 참조해 주시길 바랍니다.

워크플로우

표준 인증-코드 플로우는 다음과 같은 단계를 포함합니다.

인증 플로우

  1. 사용자가 로그인 요청을 시작: 익명의 사용자가 공개 입장에서 애플리케이션에 접근합니다. 인증을 받고자 시도하며, 세 번째 측의 애플리케이션 혹은 서비스에 대한 보호된 자원에 대한 추가적인 요청을 할 수도 있습니다.
  2. 사용자 인증: 클라이언트 애플리케이션이 인증 URI를 생성하고 이를 인증 서버에 요청을 보냅니다, 이를 통해 사용자를 그들의 로그인 페이지로 리디렉션합니다. 사용자는 다양한 로그인 방법을 사용해 로그인 페이지와 상호작용하고 인증 서버에 인증을 받습니다.
  3. 로그인 콜백 처리: 성공적인 인증 이후, 사용자는 인증 상태와 요청된 권한 데이터에 연결된 모든 관련 권한을 포함하는 authorization_code가 부여된 상태로 애플리케이션으로 리디렉션됩니다.
  4. 토큰 교환: 위의 리디렉트 주소에서 추출된 authorization_code를 사용해 토큰 교환을 요청합니다. 반환됩니다 :
    • id_token: 인증된 사용자에 대한 신원 정보를 포함하는 디지털 서명 JWT입니다.
    • access_token: 사용자 기본 정보 엔드포인트에 접근하기 위해 사용할 수 있는 불투명 access_token입니다.
    • refresh_token: 사용자가 access_token에 대해 지속적인 교환을 유지하게 해주는 자격 증명 토큰입니다.

인가 플로우

  1. 사용자 정보 접근: 애플리케이션은 초창기 토큰 교환 흐름에서 얻은 불투명 access_token을 이용해서 사용자 정보 엔드포인트에 추가 요청을 보낼 수 있습니다. 이를 통해 사용자의 이메일 주소나 프로필 사진과 같은 사용자에 대한 추가적인 세부 정보를 얻을 수 있습니다.
  2. 보호된 리소스에 대한 접근 권한 허용: 필요한 경우, 애플리케이션이 refresh_tokenresource 그리고 scope 파라미터와 함께 토큰 교환 엔드포인트에 추가 요청을 보내, 사용자가 타겟 리소스에 접근하기 위한 전용 access_token을 얻을 수 있습니다. 이 과정은 보호된 리소스에 접근하기 위한 필요한 모든 인가 정보를 포함하는 JWT 형식의 access_token을 발행하는 결과로 이어집니다.

구현

우리는 우리의 @logto/client JavaScript SDK에 있는 몇몇 디자인 전략을 따라, 당신의 고유한 클라이언트 애플리케이션을 위한 간단한 SDK를 구현하는 과정을 보여줄 것입니다. 당신이 어떤 클라이언트 프레임워크를 사용하고 있는지에 따라 상세한 코드 구조는 달라질 수 있다는 것을 명심해 주세요. 당신의 고유한 SDK 프로젝트에 대한 예제로 Logto의 공식 SDK 중 어떤 것을 선택하든 자유롭게 선택할 수 있어야 합니다.

미리보기

생성자

생성자는 logtoConfig를 입력으로 받아야 합니다. 이는 이 SDK를 통해 auth 연결을 설정하는 데 필요한 모든 필수적인 config를 제공합니다.

당신이 SDK를 위해 사용하는 플랫폼이나 프레임워크에 따라, 당신은 생성자에 지속적인 로컬 저장소 인스턴스를 전달할 수 있습니다. 이 저장소 인스턴스는 모든 권한 관련 토큰과 서크릿을 저장하는 데 사용될 것입니다.

사용자 인증 초기화

인증 요청 URL을 생성하기 전에, 안전한 프로세스를 보장하기 위해 몇 가지 준비 단계를 완료하는 것이 필수적입니다.

인증 서버에서 OIDC 설정 가져오기

`getOidcConfigs``라는 비공개 메서드를 정의해 인증 서버의 발견 엔드포인트에서 OIDC 구성을 가져와 주세요. OIDC 구성들의 응답은 클라이언트가 인증 서버와 상호작용하기 위해 사용할 수 있는 모든 메타데이터 정보를 포함하고 있습니다. 이에는 그들의 엔드포인트 위치와 서버의 기능이 포함됩니다. (OAuth OAuth Authorization Server Metadata Specs을 참조해 주세요.)

PKCE 생성자

PKCE(Proof Key for Code Exchange) 유효성 검사 흐름은 모든 공개 클라이언트 인증 코드 교환 흐름에 필수적입니다. 이는 authorization_code 침투 공격의 위험을 줄입니다. 따라서 code_challengecode_verifier는 모든 공개 클라이언트 애플리케이션(e.g. 네이티브 앱 및 SPA) 인증 요청에 필요합니다.

구현 방법은 언어와 사용 중인 프레임워크에 따라 다를 수 있습니다. 상세한 정의에 대해서는 code_challengecode_verifier 스펙을 참조하십시오.

상태 파라미터 생성하기

인증 흐름에서, state parameter는 클라이언트에 의해 보낸 인증 요청에 포함된 임의로 생성된 값입니다. 이는 CSRF(Cross-site request forgery) 공격을 방지하기 위한 보안 수단 역할을 합니다.

중간 세션 정보 저장하기

사용자가 인증되고 클라이언트 측으로 리디렉션된 후 검증을 위한 용도로 저장소에 보존해야 하는 여러 파라미터들이 있습니다. 우리는 이 중간 파라미터들을 저장소에 넣는 메서드를 구현하려고 합니다.

로그인하기

위에서 구현된 모든 것을 종합하여, 사용자 로그인 URL을 생성하고 사용자를 인증 서버로 리디렉션해 인증 받을 수 있도록 하는 메서드를 정의해 보겠습니다.

사용자 로그인 콜백 처리하기

이전 섹션에서는 사용자 인증을 위한 URL을 생성하는 로그인 메서드를 생성했습니다. 이 URL은 클라이언트 앱에서 인증 흐름을 시작하기 위해 필요한 모든 파라미터를 포함하고 있습니다. 메서드는 사용자를 인증을 위해 인증 서버의 로그인 페이지로 리디렉션합니다. 로그인이 성공적으로 이루어진 후, 종단 사용자는 위에서 제공한 redirect_uri 위치로 리디렉션됩니다. 모든 필요한 파라미터들이 redirect_uri에 담겨 있을 것이며, 이를 토대로 이어진 토큰 교환 플로우를 완료합니다.

콜백 URL 추출 및 검증

이 검증 단계는 각종 위조된 인증 콜백 공격을 막는 데 굉장히 중요합니다. 콜백 URL은 추가적인 코드 교환 요청을 인증 서버에 보내기 전에 정확하게 검증되야 해야 합니다. 먼저, 우리는 app 저장소에서 signInSession 데이터를 검색해야 합니다.

그리고 나서 토큰 교환 요청을 보내기 전에 콜백 URL의 파라미터를 검증합니다.

  • 기존에 저장했던 redirectUri를 사용해 callbackUri가 우리가 인증 서버에 보낸 것과 동일한지 검증합니다.
  • 기존에 저장했던 state를 사용해 반환된 state가 우리가 인증 서버에 보낸 것과 동일한지 검증합니다.
  • 인증 서버가 반환한 오류가 있는지 확인합니다
  • 반환된 authorization_code의 존재 여부를 확인합니다

코드 교환 요청 보내기

사용자 인증 흐름의 마지막 단계로, 우리는 반환된 authorization_code를 사용해 필요한 인증 토큰을 획득하기 위해 토큰 교환 요청을 보낼 것입니다. 요청 파라미터의 자세한 정의를 위해서는 토큰 교환 규격을 참조하세요.

  • code: 콜백 URI로부터 받은 authorization_code
  • clientId: 애플리케이션 ID
  • redirectUri: 사용자에게 로그인 URL을 생성하기 위해 사용한 것과 같은 값입니다.
  • codeVerifier: PKCE 코드 검증자. redirectUri와 마찬가지로, 인증 서버는 이 값을 이전에 보냈던 것과 비교해 들어오는 토큰 교환 요청의 유효성을 확인할 것입니다.

로그인 콜백 처리하기

우리가 가진 모든 것을 종합해 보겠습니다. signInCallback 처리 메서드를 만들어 보겠습니다:

결과적으로, 토큰 교환 요청은 다음 토큰들을 반환할 것입니다 :

  • id_token: OIDC idToken, 인증된 사용자에 대한 신원 정보를 포함하는 JSON Web Token (JWT)입니다. id_token은 사용자 인증 상태에 대한 단일 출처 (Single Source of Truth, SSOT)로 사용될 수 있습니다.
  • access_token: 인증 서버에 의해 반환된 기본 인증 코드입니다. 이를 사용해 사용자 인포 엔드포인트를 호출하고 인증된 사용자 정보를 검색할 수 있습니다.
  • refresh_token: (오프라인 접근 범위가 인증 요청에 존재할 경우) 이 리프레시 토큰은 클라이언트 애플리케이션이 사용자를 다시 인증하지 않고도 새로운 액세스 토큰을 얻을 수 있게 해줍니다, 이는 장기적인 자원 접근을 허용합니다.
  • expires_in: 액세스 토큰이 유효한 시간, 초 단위의 기간입니다.

ID 토큰 검증

id_token을 검증하고 권한을 추출하는 것은 인증 과정에서 중요한 단계로 토큰의 진정성과 무결성을 보장하기 위한 것입니다. idToken을 검증하는데 관여하는 주요 단계들은 아래와 같습니다.

  • 서명 검증: id_token은 인증 서버에 의해 그들의 개인 키를 사용해 디지털로 서명되었습니다. 클라이언트 애플리케이션은 인증 서버의 공개 키를 사용해 서명을 검증해야 합니다. 이는 토큰이 조작되지 않았으며 정당한 인증 서버에 의해 발행되었음을 보장합니다.
  • 발행자 검증**:** id_token의 "iss" (issuer) 권한이 예상 값과 일치하는지 확인해 주세요. 이는 토큰이 정확한 인증 서버로부터 발행되었음을 나타냅니다.
  • 대상 검증: id_token의 "aud" (audience) 권한이 클라이언트 애플리케이션의 클라이언트 ID와 일치하는지 확인해 주세요. 이는 토큰이 클라이언트의
  • 만료 체크: id_token의 "iat" (issued at) 권한이 현재 시간을 넘지 않았는지 검증해 주세요. 이는 토큰이 아직 유효함을 보장하는 것입니다. 네트워크 거래 비용이 있기 때문에 우리는 받은 토큰 iat 권한을 검증할 때 발급 시간 허용치를 설정해야 합니다.

반환된 id_token는 표준적인 JSON Web Token (JWT)입니다. 당신이 사용하는 프레임워크에 따라, 여러 편리한 JWT 토큰 검증 플러그인을 찾아 토큰 디코딩 및 유효성 검증을 돕는 것을 볼 수 있습니다. 이 예제에서는 우리는 토큰 검증 및 디코딩을 돕기 위해 jose를 우리의 JavaScript SDK에서 사용할 것입니다.

사용자 정보 얻기

사용자 인증이 성공적으로 이루어진 후, 기본 사용자 정보는 인증 서버가 발행한 OIDC id_token에서 얻을 수 있습니다. 하지만 성능 고려 상, JWT 토큰의 내용은 제한됩니다. 더 자세한 사용자 프로필 정보를 얻기 위해, OIDC에 기반을 둔 인증 서버들은 기본 제공 사용자 정보 엔드포인트를 제공합니다. 이 엔드포인트는 특정 사용자 프로필 스코프의 요청을 통해 추가적인 사용자 프로필 데이터를 검색할 수 있게 해줍니다.

특정 API 리소스를 가리키지 않고 토큰 교환 엔드포인트를 호출할 때, 인증 서버는 기본적으로 "opaque" 형태의 access_token을 발행합니다. 이 access_token은 기본 사용자 프로필 데이터를 검색할 수 있게 해주는 사용자 정보 엔드포인트에 접근하는 데 사용될 수만 있습니다.

보호된 리소스 인가를 위한 액세스 토큰 얻기

대부분의 경우에서, 클라이언트 애플리케이션은 사용자 인증뿐만 아니라 특정 보호된 리소스나 API 엔드포인트에 접근하는 사용자 인가도 필요로 합니다. 여기서, 우리는 로그인 도중 얻은 refresh_token을 사용해 특정 리소스를 관리하기 위해 특별히 부여된 access_token(s)을 획득하도록 하겠습니다. 이를 통해 우리는 보호된 API에 접근할 수 있게 됩니다.

요약

우리는 클라이언트 측 앱의 사용자 인증과 인가 과정에 대해 필수 메서드 구현을 제공했습니다. 당신의 특정 시나리오에 따라, 당신은 SDK 로직을 기획하고 최적화할 수 있습니다. 플랫폼과 프레임워크의 차이점 때문에 변동이 있을 수 있다는 것을 참고해 주세요.

추가적인 자세한 내용은 Logto가 제공하는 SDK 패키지를 둘러봐 주세요. 우리는 더 많은 사용자가 개발에 참여하도록 초청하고, 우리와 함께 토론에 참여하도록 장려합니다. 당신의 피드백과 기여는 우리가 SDK의 능력을 향상시키고 확장하는 데 있어 매우 중요하게 평가될 것입니다.

부록

예약된 스코프들

당신이 초기 auth 요청 도중에 넘겨야 할 Logto 예약 스코프들. 이들 스코프들은 OIDC-예약 혹은 Logto-예약 기본 스코프들로, 성공적인 인증 흐름을 완성시키기 위해 필요할 것입니다.

스코프 이름설명
openid인증이 성공한 후에 id_token을 부여받기 위해 필요합니다.
offline-accessaccess_token을 화면 밖에서 교환하고 갱신할 수 있게 해주는 refresh_token이 부여되도록 해줍니다.
profile기본 사용자 정보에 접근을 허가받기 위해 필요합니다.

Logto Config

속성 이름유형필수설명기본 값
appId문자열고유한 애플리케이션 식별자입니다. 클라이언트 애플리케이션을 식별하기 위해 인증 서버에 의해 생성되었습니다.
appSecret문자열애플리케이션 비밀 정보는 애플리케이션 ID와 함께 요청자의 신원을 확인하는데 사용됩니다. 이는 Go 웹이나 Next.js 웹 앱과 같은 기밀 클라이언트에 필요하며, 네이티브나 단일 페이지 애플리케이션(SPA)과 같은 공개 클라이언트에는 선택적입니다
endpoint문자열당신의 인증 서버의 루트 엔드포인트입니다. 이 속성은 인증 요청을 생성하는 데 널리 사용될 것입니다.
scopes스트링 리스트사용자가 주어진 보호된 리소스에 접근이 허가되기 위해 필요하게 될 모든 리소스 스코프를 나타냅니다.[reservedScopes]
resources스트링 리스트사용자가 접근을 요청하게 될 모든 보호된 리소스 지표

유틸 메서드

generateRandomString