적용하기
OAuth 2.0은 사용자의 비밀번호와 같은 민감한 정보를 직접 공유하지 않고도 사용자가 허용한 범위 내에서만 서비스에 접근할 수 있게 해주는 보안 인증 방식입니다.
시작하기 전 준비사항
OAuth 2.0을 활용한 실제 개발 예제는 OAuth2를 이용한 웹 어플리케이션 제작 바로가기를 참고해주세요.
OAuth 2.0 인증을 구현하기 전에 반드시 완료해야 할 사항들입니다.
서비스 등록: 개발하신 서비스나 앱을 솔라피 앱스토어에 등록해주세요.
클라이언트 정보 발급: 등록 완료 후 클라이언트 ID와 클라이언트 시크릿을 발급받으실 수 있습니다.
클라이언트 시크릿은 최초 생성 시에만 확인 가능하므로 안전하게 보관해주세요.
인증 흐름 개요

Step 1: 사용자 인증
솔라피 로그인을 호출하기 위해 아래 URL에 필요한 쿼리 파라미터를 추가하여 솔라피 계정 소유자에게 인증을 요청합니다.
/oauth2/v1/authorize요청 예시
Host: api.solapi.com
Method: GET
/oauth2/v1/authorize
?client_id=your_client_id
&response_type=code
&redirect_uri=https://yourapp.com/callback&scope=accounts:read+users:read
&state=random_string_123 HTTP/1.1
위 요청이 성공하면 사용자는 솔라피 인증 페이지로 이동하여 앱에 권한을 부여할 수 있습니다.
참고: 솔라피 OAuth2 인증 가이드
응답 형태
요청 시 설정한
response_type에 따라 응답 형태가 달라집니다.
응답에 포함된state값을 통해 해당 요청이 어떤 사용자에 대한 요청인지 확인할 수 있습니다.
{
"code": "ADFKVJCK19JDFKL2KFJLS3388",
"state": "요청 시 전송했던 state 값"
}{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ZwUymzWAUiTxQ...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ZwUymzWAUiTxQ..."
}Step 2: 엑세스 토큰 발급
사용자 인증 완료 후 발급받은 code를 사용하여 액세스 토큰을 발급받을 수 있습니다. (response_type이 'token'인 경우 제외)
액세스 토큰: 24시간 동안 유효
리프레시 토큰: 만료기한 없음, 최초 액세스 토큰 발급 시에만 확인 가능하므로 안전하게 보관해주세요
/oauth2/v1/access_tokenPOST /oauth2/v1/access_token HTTP/1.1
Host: api.solapi.com
Content-Type: application/json
{
"grant_type": "authorization_code",
"code": "ADFKVJCK19JDFKL2KFJLS3388",
"client_id": "your_client_id",
"client_secret": "your_client_secret",
"redirect_uri": "https://yourapp.com/callback"
}{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ZwUymzWAUiTxQ...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ZwUymzWAUiTxQ...",
"token_type": "Bearer",
"expires_in": 86400
}Step 3: 엑세스 토큰으로 API 접근
발급받은 액세스 토큰을 Authorization 헤더에 포함하여 솔라피 API를 호출할 수 있습니다.
/users/v1/memberGET /users/v1/member HTTP/1.1
Host: api.solapi.com
Authorization: Bearer eyGciOiNiIsIkpXVCJ9.eyJ0NTY3ODkwIiwibWRtaW4iOnRydWV9.TJVHrcEfxjoYZgeFONFh7HgQOAuth 2.0 인증 프로세스 요약
개발한 서비스나 앱을 솔라피에 등록하여 클라이언트 ID와 시크릿을 발급받습니다
서비스에 사용자 인증 기능을 연동합니다
사용자가 솔라피 계정으로 로그인합니다
필요한 권한에 대한 사용자 동의를 받습니다
인가된 권한이 포함된 액세스 토큰을 발급받습니다
발급받은 액세스 토큰을 Request Header에 포함하여 솔라피 API를 호출합니다
Step 4: 리프레시 토큰으로 엑세스 토큰 재발급
액세스 토큰의 유효기간이 만료된 경우, 리프레시 토큰을 사용하여 새로운 액세스 토큰을 발급받을 수 있습니다.
/oauth2/v1/access_tokenPOST /oauth2/v1/access_token HTTP/1.1
Host: api.solapi.com
Content-Type: application/json
{
"grant_type": "refresh_token",
"refresh_token": "eyGciOiNiIsIkpXVCJ9.eyJ0NTYDkwIwibWaW4iOnRydWV9.TVEfxjoYZgeFONFh7HgQ"
}{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.NewAccessToken...",
"token_type": "Bearer",
"expires_in": 86400
}State 파라미터 활용 가이드
State란 무엇인가요?
state 파라미터는 OAuth 2.0 인증 과정에서 보안을 강화하기 위해 사용되는 값입니다. 주요 목적은 다음과 같습니다
CSRF 공격 방지: Cross-Site Request Forgery 공격을 차단합니다
요청 검증: 인증 요청과 응답이 동일한 세션에서 발생했는지 확인합니다
State 값 생성 및 사용 방법
생성: 인증 요청 시 고유한 임의 문자열을 생성합니다
저장: 생성된 값을 서버 세션이나 안전한 저장소에 보관합니다
전송: OAuth 인증 URL의
state파라미터로 전송합니다검증: 인증 완료 후 반환된
state값이 원래 값과 일치하는지 확인합니다
// 1. 인증 요청 시 state 생성
const state = crypto.randomBytes(16).toString('hex'); // 예: "a1b2c3d4e5f6..."
sessionStorage.setItem('oauth_state', state);
// 2. OAuth URL에 state 포함
const authUrl = `https://api.solapi.com/oauth2/v1/authorize?response_type=code&client_id=${CLIENT_ID}&state=${state}`;
// 3. 콜백에서 state 검증
const returnedState = req.query.state;
const originalState = sessionStorage.getItem('oauth_state');
if (returnedState !== originalState) {
throw new Error('State 값이 일치하지 않습니다. CSRF 공격 가능성이 있습니다.');
}
권한(Scope) 오류 처리
권한 불일치 문제
애플리케이션에서 요구하는 권한과 사용자가 실제로 승인한 권한이 다를 경우 API 호출 시 오류가 발생할 수 있습니다.
예시 상황
애플리케이션 요구 권한:
accounts:read users:read사용자 승인 권한:
accounts:read결과:
users:read관련 API 호출 시Unauthorized오류 발생
권한 오류 대응 방안
권한 확인: 토큰 발급 후 실제 부여된 권한을 확인합니다
기능 제한: 부족한 권한으로 인해 사용할 수 없는 기능을 비활성화합니다
사용자 안내: 권한 부족으로 인한 서비스 제한사항을 명확히 안내합니다
재인증 옵션: 필요시 추가 권한을 요청할 수 있는 재인증 기능을 제공합니다
try {
const response = await fetch('https://api.solapi.com/users/v1/member', {
headers: {
'Authorization': `Bearer ${ accessToken }`
}
});
if (response.status === 401) {
// 권한 부족 오류 처리
showMessage('사용자 정보 조회 권한이 없습니다. 서비스 이용에 제한이 있을 수 있습니다.');
disableUserFeatures();
}
} catch (error) {
console.error('API 호출 오류:', error);
}