# Authentication Libs
![npm](https://img.shields.io/npm/v/@mornya/auth-libs)
![node](https://img.shields.io/node/v/@mornya/auth-libs)
![types](https://img.shields.io/npm/types/@mornya/auth-libs)
![downloads](https://img.shields.io/npm/dw/@mornya/auth-libs)
![license](https://img.shields.io/npm/l/@mornya/auth-libs)

The project of JWT / JSON Authentication process library.

> This project has been created by [Vessel CLI](https://www.npmjs.com/package/@mornya/vessel).
  For a simple and quick reference about it, click [here](https://mornya.github.io/documents/guide/vessel.md).

## About
JWT/JSON을 이용한 공통 인증처리 라이브러리.

## Installation
해당 모듈을 사용할 프로젝트에서는 아래와 같이 설치한다.
```bash
$ npm install --save @mornya/auth-libs
or
$ yarn add @mornya/auth-libs
```

## Usage
최초 랜더링 되는 앱에 아래와 같이 `Auth.initialize` 메소드를 이용하여 설정 부분을 추가해주면 된다.

### `Vue.js` example
```vue
<template></template>

<script>
import { Auth } from '@mornya/auth-libs';

export default {
  created () {
    Auth.initialize({ /* ... */ });
  },
  beforeDestroy () {
    Auth.destroy();
  },
}
</script>
```

### `React.js` example
```typescript jsx
import React, { useEffect } from 'react';
import { Auth } from '@mornya/auth-libs';

type Props = {};

const ApplicationProvider: React.FC<Props> = (props) => {
  useEffect(() => {
    Auth.initialize({ /* ... */ });

    return () => {
      Auth.destroy();
    }
  }, []); // initialize only on mounted

  return <>{props.children}</>;
}

export default ApplicationProvider;
```

## Configuration
설정은 아래 샘플을 참고. 옵션에 기재된 값은 디폴트로 설정된 값이다.
```typescript
import { Auth } from '@mornya/auth-libs';

type AuthState = {};

const defaultOption: Auth.Option<AuthState> = {
  // 실행 타입 설정 (JWT | JSON), (v2.0.0 추가)
  type: 'JWT',

  // 로컬스토리지에 저장될 키 이름
  storageTokenName: 'accessToken',

  // JWT토큰이 postMessage로 전달되는지 여부
  isProvidedFromPostMessage: true,

  // 로그 출력 여부
  isShowLog: true,

  // 토큰 만료시간 알림 표시
  notifyExpiredInHour: 24,

  // 토큰 내 만료시간이 명시되어 있는 경우 키 이름 명시 (값은 second 단위)
  expiredName: 'exp',

  // 토큰 내 만료시간이 명시되어 있지 않을 경우 만료시간 명시 (값은 second 단위), (v2.0.0 추가)
  expiredIn: -1,

  // 토큰만료시점에 onExpiredToken 이벤트 발생여부 (v2.0.0 추가)
  isInvokeExpiredEvent: true,

  // 아래 Auth.on* 콜백 메소드간 서로 참조하기 위한 상태 값의 초기값
  // Auth.setState() 및 Auth.getState() 메소드를 이용하여 콜백 메소드간 값을 참조한다.
  initialState: { /* ... */ }, // Auth.Option의 제네릭으로 지정된 AuthState 타입

  // postMessage로 데이터 수신시 콜백
  // 토큰 처리 전에 서버 오리진과 데이터가 성공적으로 받아와졌는지를 체크하는 로직을 구현해준다.
  // 이후 토큰처리를 위해서는 next 함수에 파라미터로 토큰 문자열을 제공한다.
  // 그러면 제공된 토큰을 파싱하고 onAcquiredToken 콜백이 실행됨.
  // 토큰 요청을 해도 해당 onReceiveMessage 메소드가 실행되지 않는다면 origin 문제일 수 있음.
  onReceiveMessage: ({ event, next }: OnReceiveMessagePayload) => {
    if (event.origin === '**********.my-domain.com') {
      next(event.data.accessToken)
    }
    // 조건에 맞지 않을 경우 아무 처리 없음
  },

  // 파싱된 토큰 등의 데이터를 전달받으면 실행되는 콜백
  onAcquiredToken: ({ result, getState }: OnAcquiredTokenPayload) => {
    const { isExpired } = getState(); // 콜백간 사용 할 값을 읽어 옴

    // 토큰에서 사용자 정보 얻어와서 스토어에 저장
    // 여기서 만약 JWE 토큰이면 별도 처리한다.
    my_signin_func(
      result.accessToken,
      result.parsedToken,
    );
  },

  // 토큰이 앱 진입시 존재하지 않거나 이벤트 등으로 제거된 경우 콜백
  onDroppedToken: ({ result }: OnDroppedTokenPayload) => {
    if (result.isInitialTime) {
      signout();
    }
  },

  // 토큰이 만료된 경우에 실행되는 콜백 (v2.0.0 추가)
  // 리프레시 토큰 등을 이용해 토큰을 재발급 받고나서 다시 next 함수를 처리한다.
  onExpiredToken: ({ result, next, setState }: OnExpiredTokenPayload) => {
    // result.statusCode === 'EXPIRED' 인 경우

    setState({ isExpired: true }); // 콜백간 사용 할 값을 저장

    my_refresh_token_func(MY_REFRESH_TOKEN)
      .then((accessToken) => next(accessToken))
      .catch();
  },

  // 토큰 파싱 오류 등 처리 오류시 실행되는 콜백 (v2.0.0 추가)
  onInvalidToken: ({ result, next }: OnInvalidTokenPayload) => {
    console.log(result.statucCode);
    signout();
  },
};
```

## Modules in the package
본 패키지에는 아래와 같은 모듈들을 포함한다.<br>
제공되는 모듈과 메소드 사용법 등은 코드 스니핏을 참고한다.

### Auth module
Auth 모듈은 다음과 같은 메소드들을 제공한다.

#### `Auth.initialize`
위에 명시되어 있는 설정 기반 위에 추가 option을 제공하여 초기화를 수행한다.
```typescript
import { Auth } from '@mornya/auth-libs';

/* ... */

Auth.initialize({
  storageTokenName: 'myTokenStorageName',
  onAcquiredToken () {},
  onExpiredToken () {},
  onDroppedToken () {},
  onInvalidToken () {},
});
```

#### `Auth.saveToken`
만료일시와 함께 스토리지에 키 값을 저장하도록 한다.
```typescript
import { Auth } from '@mornya/auth-libs';

/* ... */

// 3600초 후에 만료되는 값으로 로컬 스토리지에 저장한다.
// 스토리지에서 제거하려면 window.localStorage.removeItem()을 사용한다.
Auth.saveToken('foo', 'bar', 3600);
```

#### `Auth.destroy`
사용된 자원 해제를 수행한다.
```typescript
import { Auth } from '@mornya/auth-libs';

/* ... */

Auth.destroy();
```

#### `Auth.setState` / `Auth.getState`
Auth.on* 콜백 메소드간 서로 참조할 상태 값을 얻어오거나 저장한다.
```typescript
import { Auth } from '@mornya/auth-libs';

type AuthState = {
  accessToken: string;
};

/* ... */

Auth.initialize<AuthState>({
  storageTokenName: 'myTokenStorageName',
  // 초기 상태 값을 선언
  initialState: {
    accessToken: '',
  },
  onAcquiredToken () {
    const accessToken = 'xxxx.xxxx';
    Auth.setState<AuthState>({ accessToken });
    console.info('Newly acquired access token:', accessToken);
  },
  onExpiredToken () {
    const { accessToken } = Auth.getState<AuthState>();
    console.info('Expired previous access token:', accessToken);
  },
});
```

### `Auth.checkTokenStatus`
accessToken 및 refreshToken에 대한 토큰 정보를 추출하여 제공한다.
```typescript
function checkTokenStatus(token: string | undefined | null = ''): Result {}
```

### `Auth.resolveToken`
accessToken을 API를 통해 받아온 후 바로 처리를 위한 메소드.<br>
(일반적으로 로컬스토리지 등에 저장하면 처리가 자동으로 이루어지지만, 그렇지 않고 바로 처리를 위한 경우에 대한 대응 메소드)
```typescript
function resolveToken(token: string | undefined | null = ''): void {}
```

## Change Log
프로젝트 변경사항은 [CHANGELOG.md](CHANGELOG.md) 파일 참조.

## License
프로젝트 라이센스는 [LICENSE](LICENSE) 파일 참조.
