getSecretKey() . ':')); } /** * 토스 실 본인인증 사용 여부 */ protected function getTossCertIsTest(): bool { return config('toss_cert_is_test', 0); } /** * 토스 카드사 정보 */ protected function getCards(): array { return [ '3K' => '기업비씨', '46' => '광주', '71' => '롯데', '30' => '산업', '31' => 'BC카드', '51' => '삼성카드', '38' => '새마을', '41' => '신한', '62' => '신협', '36' => '씨티', '33' => '우리', 'W1' => '우리', '37' => '우체국', '39' => '저축', '35' => '전북', '42' => '제주', '15' => '카카오뱅크', '3A' => '케이뱅크', '24' => '토스뱅크', '21' => '하나', '61' => '현대', '11' => '국민', '91' => '농협', '34' => '수협' ]; } /** * 토스 은행/증권사 정보 */ protected function getBanks(): array { return [ '39' => '경남은행', '34' => '광주은행', 'S8' => '교보증권', '12' => '단위농협(지역농축협)', 'SE' => '대신증권', 'SK' => '메리츠증권', 'S5' => '미래에셋증권', 'SM' => '부국증권', '32' => '부산은행', 'S3' => '삼성증권', '45' => '새마을금고', '64' => '산림조합', 'SN' => '신영증권', 'S2' => '신한금융투자', '88' => '신한은행', '48' => '신협', '27' => '씨티은행', '20' => '우리은행', '71' => '우체국예금보험', 'S0' => '유안타증권', 'SJ' => '유진투자증권', '50' => '저축은행중앙회', '37' => '전북은행', '35' => '제주은행', '90' => '카카오뱅크', '288' => '카카오페이증권', '89' => '케이뱅크', '92' => '토스뱅크', 'ST' => '토스증권', 'SR' => '펀드온라인코리아(한국포스증권)', 'SH' => '하나금융투자', '81' => '하나은행', 'S9' => '하이투자증권', 'S6' => '한국투자증권', 'SG' => '한화투자증권', 'SA' => '현대차증권', '54' => '홍콩상하이은행', 'SI' => 'DB금융투자', '31' => 'DGB대구은행', '03' => 'IBK기업은행', '06' => 'KB국민은행', 'S4' => 'KB증권', '02' => 'KDB산업은행', 'SP' => 'KTB투자증권(다올투자증권)', 'SO' => 'LIG투자증권', '11' => 'NH농협은행', 'SL' => 'NH투자증권', '23' => 'SC제일은행', '07' => 'Sh수협은행', 'SD' => 'SK증권' ]; } /** * 카드 혜택 조회 */ protected function requestCardPromotions(): mixed { $response = Http::withHeaders([ 'Authorization' => $this->getAuthorization(), ])->get('https://api.tosspayments.com/v1/promotions/card'); $res = $response->json(); if (isset($res['interestFreeCards']) > 0) { $interestFreeCards = $res['interestFreeCards']; foreach ($interestFreeCards as $i => $row) { $res['interestFreeCards'][$i]['min'] = min($row['installmentFreeMonths']); $res['interestFreeCards'][$i]['max'] = max($row['installmentFreeMonths']); $res['interestFreeCards'][$i]['minimumPaymentAmountKor'] = $this->numberToHangul($row['minimumPaymentAmount']); } } return $res; } /** * 결제 승인 API 호출 */ protected function requestPayment(string $paymentKey, string $orderId, int $amount): mixed { // 기본 결제 요청 $response = Http::withHeaders([ 'Authorization' => $this->getAuthorization(), 'Content-Type' => 'application/json' ])->post('https://api.tosspayments.com/v1/payments/confirm', [ 'paymentKey' => $paymentKey, 'orderId' => $orderId, 'amount' => $amount ]); return $response->json(); } /** * 결제 취소 API 호출 */ protected function requestCancel(string $paymentKey, string $idempotencyKey, CancelData $cancelData): mixed { // 기본 결제 요청 $response = Http::withHeaders([ 'Authorization' => $this->getAuthorization(), 'Content-Type' => 'application/json', 'Idempotency-Key' => $idempotencyKey, ])->post(sprintf('https://api.tosspayments.com/v1/payments/%s/cancel', $paymentKey), $cancelData->toArray() ); return $response->json(); } /** * 본인확인 Access Token 요청 */ protected function requestAccessToken(Request $request): ?array { $tossCertIsTest = $this->getTossCertIsTest(); if (!$request->hasCookie('tossAccessToken')) { $token = Http::asForm()->post('https://oauth2.cert.toss.im/token', [ 'grant_type' => 'client_credentials', 'client_id' => ($tossCertIsTest ? config('test_toss_cert_client_id') : config('live_toss_cert_client_id')), 'client_secret' => ($tossCertIsTest ? config('test_toss_cert_client_secret') : config('live_toss_cert_client_secret')), 'scope' => 'ca' ])->json(); } else { $token = unserialize($request->cookie('tossAccessToken')); if ($token['tossCertIsTest'] != $tossCertIsTest) { Cookie::expire('tossAccessToken'); $token = $this->requestAccessToken($request); } } return ($token + ['tossCertIsTest' => $tossCertIsTest]); } /** * 본인확인 요청 */ protected function requestUserAuth(array $token, AuthData $authData): object|array|null { return Http::asJson()->withHeaders([ 'Authorization' => sprintf("%s %s", $token['token_type'], $token['access_token']) ])->post('https://cert.toss.im/api/v2/sign/user/auth/id/request', $authData->toArray())->object(); } /** * 본인확인 상태 조회 */ protected function requestUserAuthStatus(array $token, string $txId): object|array|null { return Http::asJson()->withHeaders([ 'Authorization' => sprintf("%s %s", $token['token_type'], $token['access_token']) ])->post('https://cert.toss.im/api/v2/sign/user/auth/id/status', [ 'txId' => $txId, ])->object(); } /** * 본인확인 결과 확인 */ protected function requestCertResult(array $token, string $txId, string $sessionKey): object|array|null { return Http::asJson()->withHeaders([ 'Authorization' => sprintf("%s %s", $token['token_type'], $token['access_token']) ])->post('https://cert.toss.im/api/v2/sign/user/auth/id/result', [ 'txId' => $txId, 'sessionKey' => $sessionKey ])->object(); } /** * 본인확인 결과 조회 */ protected function getTossCertResult(array $token, string $txId): ?object { $sessionId = $this->generateSessionId(); $secretKey = $this->generateRandomBytes(32); $iv = $this->generateRandomBytes(12); $sessionKey = $this->generateSessionKey($sessionId, $secretKey, $iv); $result = $this->requestCertResult($token, $txId, $sessionKey); if ($result->resultType == 'FAIL') { return $result; } $personalData = $result->success->personalData; $result->success->personalData = (object)[ 'ci' => $this->decryptData($secretKey, $iv, $personalData->ci), 'name' => $this->decryptData($secretKey, $iv, $personalData->name), 'birthday' => $this->decryptData($secretKey, $iv, $personalData->birthday), 'gender' => $this->decryptData($secretKey, $iv, $personalData->gender), 'nationality' => $this->decryptData($secretKey, $iv, $personalData->nationality), 'di' => $this->decryptData($secretKey, $iv, $personalData->di) ]; return $result; } }