본문으로 건너뛰기

Web

소개

PASSPORT 로그인 이 제공하는 인증 및 인가 서비스에 대해 별도의 사용자 인터페이스 로직 없이 어플리케이션을 운용할 수 있는 웹 전용 SDK 입니다.

해당 SDK는 SPA(Single Page App) 기반의 Javascript 웹 어플리케이션 환경에서 동작하며 OAuth 2.0 authorization code + PKCE flow 권한 부여에 대한 클라이언트 코드 베이스를 제공합니다.


개발 프로세스

PASSPORT 로그인 웹 SDK를 사용한 공통 개발 프로세스는 다음과 같습니다.


전체 프로세스


React 라이브러리에 대해선 별도 React를 제공하고 있습니다. 만약 Vue, Angular 등과 같은 기타 SPA 기반 프레임워크 사용 시엔, 제공된 Javescript SDK를 활용하여 각 개발 환경에 맞게 별도의 랩핑 작업이 필요할 수 있습니다.


정보설명필수 여부
프로젝트 생성웹 프론트엔드 개발 준비를 위한 프로젝트 생성REQUIRED
SDK 설치npm을 추가하여 SDK 설치REQUIRED
서비스 개발각 서비스 및 프레임워크별 개발 프로세스 작업OPTIONAL

개발 요구 사항

PASSPORT 로그인 웹 SDK는 Internet Explorer(IE)를 제외한 특정 버전 이상의 웹 브라우저 상에서 동작합니다.
브라우저별 최소 요구 사항은 다음과 같습니다.


구분항목버전 (Released)지원 범위
웹 브라우저Chrome^5 (2010-05-25)Full support
웹 브라우저Firefox^29 (2014-04-29)Full support
웹 브라우저Safari^16 (2022-09-12)Full support
웹 브라우저Edge(Chromium)^79 (2020-01-15)Full support

현재 개발 환경이 위 사항에 해당하지 않는 경우, 다음과 같은 기능들을 사용할 때 제약이 있습니다.

  • refresh token rotation 등과 같은 주요 내부 API 사용
  • MessageEvent 기반 인증 관련 인터페이스 사용
  • refresh token 관리를 위한 in-memory cache storage 사용

이해 하기

Authentication Interface

PASSPORT 로그인 웹 SDK는 인증과 관련된 작업을, 활성화된 브라우저 탭의 메인 스레드와는 다른 별도의 스레드에서 수행합니다.

인증 인터페이스를 분리된 스레드에서 수행하는 이유는 다음과 같습니다.

  • 각 서비스의 메인 스레드에서 웹 UI의 연산 동작이 Block 상태가 되는 것을 최소화함으로써, 자체 어플리케이션의 성능을 최적화
  • 별도의 전역 범위 내에서 실행 환경을 구축함으로써, authentication identifier에 대한 정보를 보호
  • 동일한 도메인에 대한 웹 어플리케이션들이 인증 인터페이스를 공유함으로써, 안정적인 authentication flow를 제공

단일 스레드 기반의 Javascript에서 멀티 스레드를 지원하기 위해 본 SDK에선 SharedWorker 인터페이스를 사용합니다.
SDK 사용자는 분립된 인증 인터페이스와 직접적으로 소통할 필요 없이 관련 메서드들을 호출하면 됩니다. 호출된 메서드들은 서비스에 필요한 데이터를 정제합니다.
이후 API Middleware을 통해 MessageEvent 기반으로 인증 인터페이스와 메시지를 주고 받으며 후속 작업을 위한 결과를 반환합니다.


SharedWorker 프로세스


현재 Worker Thread를 지원하지 않는 환경이거나 useWorker 옵션이 비활성화되어 있는 경우 내부적으로 MessageEvent 기반 인증 요청이 아닌, 단일 인증 API 인터페이스를 통해 관련 요청을 처리합니다. 현재 SDK를 적용하는 프로젝트가 반응형 웹앱을 지원하는 경우에도, useWorker 옵션을 비활성화하는 것을 권장합니다.

인증 관련 요청 처리


Tokens

refresh token을 보유한 모든 사람은 필요 시 새로운 access token을 얻을 수 있는 권한이 있습니다. 이는 토큰이 만료되어 잦은 재인증 절차를 거쳐야 되는 불편한 사용자 경험을 개선시킬 수 있습니다. 그러나 refresh token을 보유한 주체가 정당한 사용자임을 보장할 수 없으며 상대적으로 긴 수명 주기를 가지고 있기 때문에 유출되거나 손상될 경우에 대한 전략이 필요합니다.

이를 위해 PASSPORT 웹 SDK는 사용자 옵션애 따라 다음과 같은 보안 대응을 수행합니다.

  1. cacheLocationmemory이며 useWorker 옵션이 true인 경우, 메인 스레드와는 별도의 전역 범위 내 스레드 내에서 In-Memory Storage 방식을 통해 refresh token을 처리 및 관리합니다. 메모리 상에 캐싱된 refresh token 값은 외부에서의 CSRF(Cross-Site Request Forgery) 공격을 방지할 수 있습니다.
    또한 저장된 스코프의 위치가 메인 스레드와는 별도의 실행 컨텍스트이며 DOM에 직접 접근할 수 없으므로, XSS(Cross Site Scripting) 공격을 방지할 수 있습니다.

  2. 별도의 설정 없이도 처음 인스턴스 생성 후, Refresh token rotation에 대한 후속 작업을 자동으로 수행합니다. 따라서 상대적으로 수명이 긴 refresh token 또한 지속적으로 교환되고 무효됨에 따라 악의적인 접근 위협을 줄입니다.

Refresh token rotation은 애플리케이션이 access token을 얻기 위해 refresh token을 교환할 때마다 새로운 refresh token 또한 반환받도록 보장합니다.


반면, access token 및 id token은 디음과 같은 이유로 인해 브라우저 내 [cookie 또는 메인스레드 내 메모리에 저장합니다.

  1. 매번 접근 권한이 있는 리소스를 서버에 요청하기 전에 인증 스레드에 access token 접근 관련 메시지를 보내고 기다리는 것은 비용이 듭니다.

  2. MessageEvent 기반의 인증 인터페이스는 비동기 통신(Asynchronous communication)으로 동작하기 때문에 각 애플리케이션의 기존 서비스 동작 로직에 부수 효과(Side Effect)를 발생시킬 수 있습니다.

  3. 쿠키의 경우 동일한 도메인의 애플리케이션에 대해서 인증 정보를 공유합니다. 별도의 인증 절차 과정 없이 다른 브라우저 탭 또는 동일한 루트 도메인에서도 cookie에 저장된 인증 정보를 토대로 서비스를 바로 이용할 수 있도록 함으로써, 시용자 경험을 개선시킵니다.


Javascript

사전 작업

PASSPORT 로그인 웹 SDK를 사용하여 개발을 수행하기 전에 다음 작업이 선제되어야 합니다.


프로젝트 생성

PASSPORT 로그인 웹 SDK는 특정 브라우저 환경에서 작동하며, 일반적인 웹 프론트엔드 개발 준비가 필요합니다.


  1. 터미널을 실행하고 폴더를 생성한 후에 해당 폴더에 진입합니다.

    mkdir exmaple-passport-js
    cd example-passport-js
  2. 패키지 생성과 초기화 작업을 위해 다음 명령어를 실행합니다.

    npm init
  3. 각 개발 상황에 따라 웹 서버를 구축하고, 서버를 활성화합니다.

    # Node.js
    # Open browser "localhost:8080"

    npm i http-server
    touch index.html
    npx http-server

SDK 설치하기

PASSPORT 로그인 웹 SDK는 npm을 통해 설치할 수 있습니다.

  1. npm 명령어를 통해 SDK를 설치합니다.

    npm install @maxverse/passport-web-sdk
passport-web-sdk
  1. 해당 프로젝트 내에서 CommonJS(CJS) 또는 ECMAScript Modules(ESM) 패턴으로 SDK를 불러온 후 사용할 수 있습니다.

    import { Passport } from "@maxverse/passport-web-sdk";

    // or

    const { Passport } = require("@maxverse/passport-web-sdk");

SDK 개발

사전 작업을 완료하면, 다음과 같은 구현 사항을 통해 OAuth 클라이언트를 프로젝트 내에서 활성화할 수 있습니다.

OAuth 클라이언트는 리소스 소유자를 대신해 보호된 리소스에 접근하고자 하는 소프트웨어로서, passport client는 이에 대한 솔루션을 제공합니다.
그 외 서비스에 대한 사항은 각 도메인에 맞게 자체적인 개발 과정이 필요합니다.

현재 프로젝트가 MPA(multiple-page-application) 기반 애플리케이션인 경우, 본 SDK는 기본적으로 SPA(single-page-application) 기반의 애플리케이션을 지원하기 때문에 프로젝트 마이그레이션 작업이 추가적으로 필요할 수 있습니다. 그럼에도 MPA 애플리케이션 상에서 SDK를 사용했을 경우, PassportClientOptionscacheLocationcookie로 설정해야 합니다.


구현 사항필수 여부설명
Passport Client 생성REQUIREDpassport-js sdk에서 제공하는 Passport에 대한 인스턴스 생성
인증 기능 추가REQUIRED사용자 인증을 위한 기능 구현
사용자 프로필 조회OPTIONAL인증된 사용자에 대한 프로필 정보 조회

Passport Client 생성

@maxverse/passport-web-sdk 에서 제공하는 Passport Client의 인스턴스를 생성합니다.


  1. Passport Client는 클라이언트 사이드에서 동작하기 때문에, 웹 브라우저 내의 모든 요소가 준비가 끝난 상태여야 합니다.
    이를 위해 다음과 같이 전역 스코프 내에 window.load 이벤트 핸들러를 선언하고 관련 인스턴스를 초기화합니다.

    let passport: Passport | null = null;

    window.addEventListener("load", async () => {
    passport = new Passport();
    });

  1. 다음과 같이 Passport Client는 인증 과정에 필요한 옵션 값을 인자로 받습니다.
  • PassportClientOptions

    구분타입설명
    domainstring인증/인가 서버 도메인
    clientIdstring클라이언트 고유 식별자
    cookieDomainstring쿠키에 액세스할 수 있는 도메인
    설정하지 않으면 쿠키의 범위는 하위 도메인을 포함한 현재 도메인
    useWorkerstringworker 스레드를 활성화 여부
    true(default), false
    onLoadstring사용자가 클라이언트를 통해 자동으로 인증되도록 하는 옵션
    login-required, check-sso
    authorizationOptionsAuthorizationOptions사용자를 인가 서버의 인가 엔드 포인트로 리다이렉트 시키기 위한 질의 파라미터에 대한 옵션
    cahcheLocationstringaccess_token과 id_token을 캐싱할 위치 지정
    cookie(default), memory

    OAuth 클라이언트는 클라이언트 식별자라는 특별한 문자열로 식별되며, Passport 로그인에선 이를 client_id라는 이름으로 참조합니다.
    client_id 할당과 관련된 내용은 맥스버스 콘솔 내 패스포트 로그인 문서를 확인해 주세요.

    cookieDomain을 잘못 설정할 경우 자동 인증 기능에 문제가 발생할 수 있습니다. 사용자가 여러 하위 도메인에 걸쳐 인증 상태를 유지하려면 최상 도메인에 접두사 . 를 사용하면 됩니다 (eg: .example.com)

    login-required는 사용자가 인증되지 않는 상태일 경우 메인 페이지(eg.로그인 페이지)를 보여주며 클라이언트에선 추가적인 인증 작업을 수행하지 않습니다.
    check-sso는 사용자가 인증된 상태일 경우 서비스 페이지를 보여주지만 인증되지 않는 상태일 경우 현재 페이지 상에서 인가 엔드 포인트로 자동으로 리다이렉트 시킵니다.


  • AuthorizationOptions

    구분타입설명
    scopestring리소스에 대한 접근 권한
    openid(default), email, name, image
    redirect_uristring브라우저를 리다이렉션 할 기본 URI

    OAuth 프로토콜에서 scope는 공백으로 구분된 범위 문자열의 조합으로 표현되어, 범위를 나타내는 문자열 값에 공백이 포함되면 안됩니다. 그러나 Passport client에선 scope 문자열에 대한 공백 처리를 별도로 처리하기 때문에 허용되는 접근 권한 범위 내에서 올바른 값을 입력만 하면 됩니다.
    만약 올바른 범위 값을 입력하지 않은 경우 인가 코드 발급에 있어서 invalid_scope 에러가 발생할 수 있습니다. 자세한 명세는 패스포트 로그인 API 예시 를 참고해주세요.

    옵션에 들어가는 redirect_uri은 맥스버스 개발자 콘솔의 해당 애플리케이션 Redirect URI 섹션에 사전 등록되어 있어야 합니다. 자세한 설명은 패스포트 로그인 설정 에서 확인해주세요.


    let passport: Passport | null = null;

    const passportClientOptions = {
    domain: 'youtDomain'
    clientId: "yourClientId",
    cookieDomain: ".example.com",
    useWorker: false, // or true
    onLoad: "login-required",
    authorizationOptions: {
    redirect_uri: window.location.href,
    },
    };

    window.addEventListener("load", async () => {
    passport = new Passport(passportClientOptions);
    });

인증 기능 추가

  1. 생성된 passport 인스턴스 토대로 onLoad 메서드를 호출합니다.
    onLoad 메서드는 내부적으로 현재 인가 그랜트(Authorization grants)의 단계와 주어진 클라이언트 설정에 맞는 작업을 수행합니다.

    여기서 말한 인가 그랜트는 특정 메커니즘보단 OAuth 프로토콜의 전체 프로세스(흐름)를 의미합니다. 즉, 클라이언트가 사용자를 인가 엔드 포인트로 이동시키고, 인가 코드를 전달받고 마지막으로 인가 코드를 토큰과 교환하는 과정 전체로서 권한 위임 행위 자체를 나타내고 있습니다.

    onLoad 메서드를 빈 값과 호출 시, 기본적으로 PassportClientOptions onLoad 옵션을 사용합니다.


    let passport: Passport | null = null;

    const passportClientOptions = {
    domain: 'yourDomain'
    clientId: "youtClientId",
    cookieDomain: ".example.com",
    useWorker: false, // or true
    onLoad: "login-required",
    authorizationOptions: {
    redirect_uri: window.location.href,
    },
    };

    const init = async (passport: Passport) => {
    const onLoad =
    window.location.href === "http://localhost:8080/login"
    ? "login-required"
    : "check-sso";

    try {
    return await passport.onLoad(onLoad);
    } catch (error: any) {
    throw new Error(error);
    }
    };

    window.addEventListener("load", async () => {
    const authClient = new Passport(passportClientOptions);

    init(client).then(() => {
    passport = authClient;
    });
    });

  2. 위 예시 코드와 같이 현재 사용자가 메인 페이지(eg.로그인 페이지)에 있다면 직접 특정 이벤트를 발생시켜 loginWithRedirect 메서드를 호출해주어야 합니다.

    loginWithRedirect는 내부적으로 PKCE 스펙에 맞게 code_verifiercode_challenge를 생성합니다. 로그인 요청이 발생할 경우 사용자가 설정한 옵션과 함께 code_challenge 및 code_challenge_method(S256)를 하나의 파리미터로 빌드하여 인가 엔드 포인트로 사용자를 리다이렉트 시킵니다.



    ( ... )

    window.addEventListener("load", async () => {
    const authClient = new Passport(passportClientOptions);

    init(client).then(() => {
    passport = authClient;

    const $loginButton = document.querySelector('.login-btn');

    $loginButton.addEventListener('click', async () => {
    await passport.loginWithRedirect();
    })
    });
    });

  3. PASSPORT 로그인을 통해 사용자의 세션을 종료하기 위해 requestLogout 메서드를 관련 요소에 바인딩하여 줍니다.
    로그아웃 요청 시, 쿠키에 사용자의 id_token 이 없는 경우 내부적으로 refresh token rotation을 수행하고 재요청을 보냅니다.



    ( ... )

    window.addEventListener("load", async () => {
    const authClient = new Passport(passportClientOptions);

    init(client).then(() => {
    passport = authClient;

    ( ... )

    const $logoutButton = document.querySelector('.logout-btn');

    $logoutButton.addEventListener('click', async () => {
    await passport.requestLogout();
    })
    });
    });

  1. HTTP 클라이언트를 통한 사용자 인증 기반 리소스 서버 접근 시, updateToken 메서드를 호출하여 줍니다. updateToken은 내부적으로 사용자 인증 상태를 확인하고 인증 여부에 따라 refresh token rotation을 포함한 후속 작업을 처리합니다.

      ( ... )

    const exampleFetch = async () => {
    const { token } = await passport.updateToken();

    const exmapleHeaders = {
    'Authorization': `Bearer ${token}`
    };

    const data = await fetch('https://example.resource.com/test', {
    headers: exampleHeaders
    })
    }

React

사전 작업

passport-react 라이브러리를 사용하여 개발을 수행하기 전에 다음 작업이 선제되어야 합니다.


프로젝트 생성

PASSPORT 로그인 웹 SDK는 특정 브라우저 환경에서 작동하며, React 라이브러리에 대한 개발 환경 준비가 필요합니다. 예시 코드에선 CRA 명령어를 사용하여 React 프로젝트를 생성하겠습니다.


  1. 터미널을 실행하고 폴더를 생성한 후에 해당 폴더에 진입합니다.

    npx create-react-app example-passport-react
    cd example-passport-react
  2. 개발 서버를 활성화합니다.

     npm run dev

라이브러리 설치하기

PASSPORT 로그인 웹 SDK는 npm을 통해 설치할 수 있습니다.

  1. npm 명령어를 통해 라이브러리를 설치합니다.

    npm install @maxverse/passport-web-sdk
    npm install @maxverse/passport-react
passport-react

passport-react는 리액트 18.2.0 버전 이상을 호환합니다.

passport-react를 사용하기 위해서 의존성 모듈인 @maxverse/passport-web-sdk를 설치합니다.

  1. 해당 프로젝트 내에서 CommonJS(CJS) 또는 ECMAScript Modules(ESM) 패턴으로 SDK를 불러온 후 사용할 수 있습니다.

    import { Passport } from "@maxverse/passport-react";

    // or

    const { Passport } = require("@maxverse/passport-react");

SDK 개발

사전 작업을 완료하면, 다음과 같은 구현 사항을 통해 OAuth 클라이언트를 프로젝트 내에서 활성화할 수 있습니다.
구현 사항필수 여부설명
context Provider 선언REQUIRED앱의 루트 컴포넌트에 Provider 컴포넌트를 사용하여 전체 애플리케이션에 Context를 제공

Provider 선언 이후 내부 컴포넌트에서 관련 state 값을 usePassport hook을 통해 참조할 수 있습니다. 다음은 passport-react에서 추가적으로 제공하는 주요 값입니다.

  • initialized: 해당 값을 통해 passport 인스턴스가 정상적으로 인증 과정을 마치고 초기화되었음을 판별할 수 있습니다. 해당 값을 이용하여 사용자 인증이 필요한 API의 호출 시점을 핸들링하거나 passport 인스턴스 내 getter 및 메서드에 안정적으로 접근할 수 있습니다.

    다음은 리액트에서 데이터 관리 및 서버 상태 관리로서 많이 쓰이는 react-query를 사용한 예시입니다.

    const uuid = router.query?.uuid;
    const { initialized } = usePassport();

    /** 테스트 상세정보 조회 */
    const { data } = useQuery(["detail", uuid], () => axiosGetDetailInfo(), {
    enabled: !!uuid && initialized,
    });

    router query를 통해 uuid 값이 정상적으로 불러왔다고 하더라도 해당 단계에선 아직 api 요청을 할 수 없고 상위 Provider에서 passport 인스턴스가 초기화가 완료되어야 합니다. 이는 API 요청 처리 전에 사용되는 passport.updateToken이 있기 때문입니다. updateToken을 사용하여 인증 토큰을 참조하는데, 상위 context인 Provider 내에서 아직 transaction 단계가 진행 중인 경우 initialized는 아직 비활성화되어 있기 때문에 다음과 같은 에러가 발생합니다.


    Currently in code transaction phase, therefore access is not available

  • isAuthentiacted: 사용자 인증 여부에 따른 화면을 조건적으로 렌더링이 필요할 시 passport.isAuthenticated가 아닌 랩핑된 인증 여부 state인 isAuthentiacted를 사용하길 권장합니다. isAuthentiacted는 기본적으로 access token 및 id token의 여부만을 판별할 수 있는 값입니다. 반면 isAuthentiacted는 현재 클라이언트 애플리케이션이 refresh token roation을 수행할 수 있는지까지 판별하기 때문에 캐싱된 사용자의 정보가 없다고 하더라도 미인증된 화면을 즉각적으로 화면에 렌더링하지 않습니다.


    passport context provider


  • requestLogoutWithFallback: 기존 passport.requestLogut 메서드의 동작을 수행함과 동시에 initialized를 비활성화 함으로써, 불필요한 인증 기반 API 호출 및 인증 관련 기능에 대한 부수 효과를 방지합니다. 기본적으로 onLoad 옵션이 login-required로 설정되어 있는 경우 같이 사용하는 것을 권장합니다.

Provider 컴포넌트 선언

passport-react는 앱의 다양한 레벨에서 전역 상태를 쉽게 공유하고 관리할 수 있도록 Context API 를 사용합니다.


  1. 앱의 루트 컴포넌트에 PassportProvider 컴포넌트를 감싸줘 Context를 제공하여 줍니다.

    import { PassportProvider } from "@maxverse/passport-react";

    function Root() {
    return (
    <>
    <PassportProvider>
    <Component />
    </PassportProvider>
    </>
    );
    }

    만약 다른 전역 상태 관리 라이브러리를 사용하고 있을 경우, 각 도메인에 맞게 Context 계층을 구성하여 줍니다.

    예를 들어, recoil를 전역 상태 관리 라이브러리로써 사용하고 있고 passport-react가 제공하는 기능을 내부에서 같이 사용하기를 원하는 경우 다음 예시 코드와 같이 RecoilRoot를 PassportProvider 내부에 작성하면 됩니다.

    import { RecoilRoot } from "recoil";
    import { PassportProvider } from "@maxverse/passport-react";

    function Root() {
    return (
    <>
    <PassportProvider>
    <RecoilRoot>
    <Component />
    </RecoilRoot>
    </PassportProvider>
    </>
    );
    }

  1. onLoad 옵션을 React 라우팅 패턴에서 사용하기 위해서 다음과 같이 현재 페이지 경로에 대한 조건 판별식을 포함한 clientOptions를 초기화하여 줍니다.
    import { RecoilRoot } from "recoil";
    import { PassportProvider } from "@maxverse/passport-react";
    import { useLocation } from "react-router-dom";

    function Root() {
    const { pathname } = useLocation();

    const clientOptions = {
    domain: 'yourDomain'
    clientId: "yourClientId",
    cacheLocation: "cookie",
    onLoad: pathname === "/login-page" ? "login-required" : "check-sso",
    useWorker: false,
    authorizationOptions: {
    redirect_uri: `http://localhost:8080${pathname}`,
    },
    };

    return (
    <>
    <PassportProvider clientOptions={clientOptions}>
    <RecoilRoot>
    <Component />
    </RecoilRoot>
    </PassportProvider>
    </>
    );
    }

  2. 각 도메인에 맞는 후속 처리를 위해, 인증 성공 여부에 따라 onSuccess 또는 onError props를 선택적으로 선언할 수 있습니다.


    • onSuccess

      구분타입설명
      statusstring인증 성공 여부 상태
      SUCCESS, FAIL
      claimsClaims, null특정 사용자에 대한 정보나 속성

    • onError

      구분타입설명
      statusstring인증 성공 여부 상태
      SUCCESS, FAIL
      errorstringError 인스턴스 message

    import { RecoilRoot, useSetRecoilState } from "recoil";
    import { PassportProvider } from "@maxverse/passport-react";
    import { useLocation } from "react-router-dom";
    import { userState } from "atom/user";

    function Root() {
    const { pathname } = useLocation();
    const setUser = useSetRecoilState(userState);

    const clientOptions = {
    domain: "yourDomain",
    clientId: "yourClientId",
    cacheLocation: "cookie",
    onLoad: pathname === "/login-page" ? "login-required" : "check-sso",
    useWorker: false,
    authorizationOptions: {
    redirect_uri: `http://localhost:8080${pathname}`,
    },
    };

    const onSuccess = (result) => {
    if (!result.claims) {
    return;
    }

    setUser(result.claims);
    };

    const onError = (result) => {
    console.warn(result.status, result.message);
    };

    return (
    <>
    <PassportProvider
    clientOptions={clientOptions}
    onSuccess={onSuccess}
    onError={onError}
    >
    <RecoilRoot>
    <Component />
    </RecoilRoot>
    </PassportProvider>
    </>
    );
    }

리액트 앱 내부에서 사용하기

앱 내부에서 생성된 Passport 인스턴스를 전역적으로 사용하기 위해서 usePassport custom hook을 사용합니다.

  1. 로그인하기

    import { usePassport } from "@maxverse/passport-react";

    function LoginPage() {
    const { passport } = usePassport();

    const onLogin = async () => {
    await passport.loginWithRedirect();
    };

    return (
    <>
    <button handler={onLogin}>passport 계정으로 로그인</button>
    </>
    );
    }

    export default LoginPage;

    만약 nextjs 프레임워크를 사용하고 있다면 이벤트 처리 외에 passport 인스턴스를 동기적으로 사용하면 안됩니다.

    passport-react는 기본적으로 nextjs의 SSR 프레임워크 방식을 지원하고 있으며 서버사이드 렌더링 시엔 주입된 더미(dummy) 데이터를 사용하기 때문에 비동기적인 방식으로 관련 기능을 구현해야 합니다.

    // nextjs

    import { useEffect } from "react";
    import { useRouter } from "next/router";
    import { usePassport } from "@maxverse/passport-react";

    function LoginPage() {
    const router = useRouter();
    const { initialized, passport } = usePassport();

    const onLogin = async () => {
    await passport.loginWithRedirect();
    };

    useEffect(() => {
    if (initialized && passport.isAuthenticated) {
    router.push("/service");
    }
    }, [initialized, passport, router]);

    return (
    <>
    <button handler={onLogin}>passport 계정으로 로그인</button>
    </>
    );
    }

    export default LoginPage;

  1. 현재 모듈이 PassportProvider 트리 내부 범위 내에 속하지 않거나 리액트 컴포넌트가 아닌 일반 모듈일 경우엔 getPassportInstance 헬퍼 함수를 사용합니다.

    아래 코드는 프로젝트 내부에서 axios 라이브러리를 사용한다는 전제 하에, 작성한 interceptors 관련 일반 모듈입니다.

    const setInterceptors = (axiosService: AxiosInstance): AxiosInstance => {
    axiosService.interceptors.request.use(
    async (config: AxiosRequestConfig): Promise<AxiosRequestConfig> => {
    if (!config.headers) {
    config.headers = {};
    }

    const passport = getPassportInstance({
    domain: "yourDomain",
    clientId: "yourClientId",
    useWorker: true, // or false
    });

    const { token } = await passport.updateToken();

    config.headers["Authorization"] = `Bearer ${token}`;

    return config;
    }
    );
    };

    현재 cacheLocation이 memory인 경우 getPassportInstance 헬퍼 함수를 사용할 수 없습니다.
    이 경우 사용하고자 하는 일반 모듈을 React Context Tree 내부에 종속시키도록 코드를 수정해야 됩니다.

    getPassportInstance로 passport 인스턴스 생성 시, 처음 context Provider에 설정된 옵션 값과 동일하게 설정해야 정상적인 동작을 보장합니다.