OAuth 연동하기
모두싸인은 OAuth 2.0 Authorization Code Grant 방식을 지원하며, RFC 6749 최종 스펙을 기반으로 합니다.
이럴 때 사용합니다외부 서비스에서 모두싸인 기능을 제공하고 싶을 때 사용합니다. 사용자가 권한을 허가하면, 허가된 범위 내에서 외부 서비스가 사용자를 대신해 모두싸인 API를 호출할 수 있습니다.
시작 전 준비 사항
- 모두싸인 계정(애플리케이션 관리용)
- 고객센터를 통해 등록한 OAuth 애플리케이션
- 발급받은
clientId와clientSecret
clientSecret 취급 주의
clientSecret은 애플리케이션의 패스워드 역할을 합니다. 절대 외부에 노출하지 마세요. 반드시 서버사이드에서만 처리해야 하며, 브라우저나 모바일 앱에서 직접 사용하는 것은 심각한 보안 취약점이 됩니다.
전체 인증 흐름
고객센터를 통해 OAuth 애플리케이션을 등록하고 clientId / clientSecret을 발급받습니다.
사용자를 인가 페이지로 리디렉션하여 권한 동의를 받고 Authorization Code를 수신합니다.
Authorization Code를 Access Token으로 교환합니다.
Access Token으로 API를 호출하고, 만료 시 Refresh Token으로 갱신합니다.
1. 애플리케이션 등록
시작에 앞서현재 애플리케이션 등록은 모두싸인 고객센터 혹은 기술지원 매니저를 통해서만 신청 가능합니다. OAuth 기능 이용에 대한 문의도 동일하게 연락 부탁드립니다.
등록 시 필요한 정보
| 항목 | 필수 여부 | 설명 |
|---|---|---|
| 애플리케이션 이름 | ✅ | 사용자 인가 페이지에 표시되는 서비스 이름 |
| 애플리케이션 소유자 | ✅ | 모두싸인 계정의 이름 및 이메일 |
| Redirect URIs | ✅ | Authorization Code를 수신할 콜백 URL (여러 개 등록 가능) |
| 홈페이지 주소 | ➖ | 인가 페이지에 표시되는 서비스 URL |
| 프로필 이미지 | ➖ | 인가 페이지에 표시되는 서비스 로고 |
| 허용 IP 목록 | ➖ | 인가 요청을 허용할 서버 IP 화이트리스트 (미설정 시 IP 제한 없음) |
발급받는 자격증명
| 자격증명 | 설명 |
|---|---|
clientId | 애플리케이션 식별자. API 요청에 공개적으로 포함됩니다. |
clientSecret | 애플리케이션 비밀키. 서버 사이드에서만 사용하세요. |
2. 인가 요청 및 Authorization Code 발급
사용자를 아래 주소로 리디렉션해 권한 동의를 받습니다.
GET https://app.modusign.co.kr/oauth/authorize
요청 파라미터
| 파라미터 | 필수 여부 | 설명 |
|---|---|---|
response_type | ✅ | code로 고정 |
client_id | ✅ | 발급받은 애플리케이션 clientId |
redirect_uri | ✅ | Authorization Code를 수신할 콜백 URI. URL 인코딩이 필요하며, 등록된 URI만 허용됩니다. |
state | ✅ | CSRF 방지용 임의 문자열. URL 인코딩이 필요하며, 응답 시 동일한 값이 반환됩니다. |
요청 URL 예시
https://app.modusign.co.kr/oauth/authorize?response_type=code&client_id=01FQE43XG5KAAA3ZKL4DFQ1S66&state=8759367&redirect_uri=https%3A%2F%2Fsite.com%2Fcallback
인가 페이지 살펴보기
사용자에게는 아래와 같은 인가 페이지가 표시됩니다. 사용자가 모두싸인에 로그인되어 있지 않다면 로그인을 먼저 거친 뒤 원래의 인가 요청으로 돌아옵니다.
| 화면 항목 | 설명 |
|---|---|
| 연결할 계정 | 현재 로그인되어 있는 모두싸인 계정입니다. 다른 계정으로 연결하려면 다른 계정으로 로그인을 누릅니다. |
| 연결할 워크스페이스 | 이 앱이 접근할 워크스페이스를 선택합니다. 아래 「연결할 워크스페이스 선택하기」를 참고하세요. |
| 이 앱에 허용할 접근 범위 | 앱이 요청한 권한이 제품별 항목으로 표시됩니다. 필수로 표시된 항목은 항상 켜진 상태로 부여되고, 선택 항목은 사용자가 끌 수 있습니다. |
인가 페이지에는 연결의 성격을 설명하는 안내문도 함께 표시됩니다. 앱은 사용자 계정의 권한 범위 안에서만 접근하므로 사용자가 볼 수 없는 문서는 앱도 볼 수 없으며, 브라우저를 닫아도 사용자가 계정 설정에서 연결을 끊기 전까지 접근이 유지됩니다.
연결할 워크스페이스 선택하기
워크스페이스는 문서·템플릿·요금제가 귀속되는 단위입니다. OAuth 연결은 사용자가 선택한 워크스페이스 하나에만 적용되며, 앱은 그 워크스페이스의 자원에만 접근할 수 있습니다.
화면이 열릴 때 워크스페이스가 미리 선택되어 있는지는 사용자가 가진 워크스페이스 구성에 따라 다릅니다.
| 사용자의 워크스페이스 구성 | 화면 동작 |
|---|---|
| 워크스페이스가 하나뿐인 경우 | 해당 워크스페이스가 선택된 상태로 열립니다. 그대로 연결하기를 누르면 됩니다. |
| 개인·공용이 하나씩인 경우 | 공용 워크스페이스가 선택된 상태로 열립니다. 그대로 연결하기를 누르면 됩니다. |
| 워크스페이스가 여러 개인 경우 | 미리 선택되지 않습니다. 사용자가 직접 고르기 전까지 연결하기 버튼이 비활성 상태로 유지됩니다. |
워크스페이스를 바꿔 선택할 때 주의하세요잘못된 워크스페이스를 선택하면 문제가 생길 수 있습니다. 특히 개인 워크스페이스에는 요금제가 활성화되어 있지 않은 경우가 많고, 이때 연결 자체는 성공하지만 이후 서명 요청 등 API 호출이 실패하게 됩니다. 연결 직후에는 문제가 드러나지 않다가 실제 업무에서 오류로 나타나기 때문에 원인을 찾기 어렵습니다.
잘못 연결하셨을 경우, 가이드의 6번 항목을 통해 연결을 끊고 재연동이 필요합니다.
사용자가 허용한 경우
사용자가 연결하기를 누르면 redirect_uri로 아래와 같이 리디렉션됩니다.
https://site.com/callback?code=94228db4tt12&state=8759367
| 파라미터 | 설명 |
|---|---|
code | Access Token 발급에 사용할 Authorization Code |
state | 요청 시 전달한 state 값. CSRF 검증에 사용합니다. |
사용자가 거부한 경우
사용자가 취소를 누르면 아래와 같이 리디렉션 됩니다.
https://site.com/callback?error=access_denied
안내사항다른 계정으로 재연결하거나 세션을 초기화할 때는 아래 URL을 호출해 모두싸인 계정을 로그아웃 처리하세요.
https://app.modusign.co.kr/signout?redirectTo=${encodeURIComponent('https://modusign.co.kr')}
redirectTo를 지정하지 않으면 모두싸인 로그인 페이지로 이동합니다.
3. Access Token 발급
POST https://api.modusign.co.kr/oauth/token
요청 파라미터
| 파라미터 | 필수 여부 | 설명 |
|---|---|---|
grant_type | ✅ | "authorization_code"로 고정 |
client_id | ✅ | 애플리케이션 clientId |
client_secret | ✅ | 애플리케이션 clientSecret |
code | ✅ | 2단계에서 발급받은 Authorization Code |
redirect_uri | ✅ | Authorization Code 발급 시 사용한 redirect_uri와 동일해야 합니다. |
curl --request POST \
--url https://api.modusign.co.kr/oauth/token \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"grant_type": "authorization_code",
"client_id": "CLIENT-ID",
"client_secret": "CLIENT-SECRET",
"code": "AUTHORIZATION-CODE",
"redirect_uri": "https://site.com/callback"
}'const fetch = require('node-fetch');
const response = await fetch('https://api.modusign.co.kr/oauth/token', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
grant_type: 'authorization_code',
client_id: 'CLIENT-ID',
client_secret: 'CLIENT-SECRET',
code: 'AUTHORIZATION-CODE',
redirect_uri: 'https://site.com/callback'
})
});
const data = await response.json();
console.log(data);응답
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"refresh_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 1800
}| 필드 | 설명 |
|---|---|
access_token | API 호출 시 Authorization 헤더에 사용하는 JWT. 유효 기간 30분 |
refresh_token | access_token 만료 후 재발급에 사용하는 JWT. 유효 기간 60일 |
token_type | 항상 "Bearer" |
expires_in | access_token 유효 시간(초). 1800 = 30분 |
발급받은 토큰은 사용자가 선택한 워크스페이스에 대한 접근 권한을 갖습니다. 다른 워크스페이스로 바꾸려면 연결을 끊고 다시 인가를 받아야 합니다.
4. Access Token으로 API 호출
발급받은 access_token을 Authorization 헤더에 담아 호출합니다.
Authorization: Bearer {access_token}
curl --request GET \
--url 'https://api.modusign.co.kr/documents?offset=0&limit=10' \
--header 'Authorization: Bearer {access_token}'const fetch = require('node-fetch');
const response = await fetch('https://api.modusign.co.kr/documents?offset=0&limit=10', {
method: 'GET',
headers: {
'Authorization': 'Bearer {access_token}'
}
});
const data = await response.json();
console.log(data);5. Access Token 갱신
access_token은 30분 후 만료됩니다. 만료되면 저장해 둔 refresh_token으로 새 토큰을 발급받으세요.
POST https://api.modusign.co.kr/oauth/token
요청 파라미터
| 파라미터 | 필수 여부 | 설명 |
|---|---|---|
grant_type | ✅ | "refresh_token"으로 고정 |
client_id | ✅ | 애플리케이션 clientId |
client_secret | ✅ | 애플리케이션 clientSecret |
refresh_token | ✅ | 보유 중인 refresh_token |
curl --request POST \
--url https://api.modusign.co.kr/oauth/token \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"grant_type": "refresh_token",
"client_id": "CLIENT-ID",
"client_secret": "CLIENT-SECRET",
"refresh_token": "REFRESH-TOKEN"
}'const fetch = require('node-fetch');
const response = await fetch('https://api.modusign.co.kr/oauth/token', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
grant_type: 'refresh_token',
client_id: 'CLIENT-ID',
client_secret: 'CLIENT-SECRET',
refresh_token: 'REFRESH-TOKEN'
})
});
const data = await response.json();
console.log(data);
Refresh Token 갱신 규칙응답의
refresh_token필드는 기존 Refresh Token의 잔여 유효기간이 30일 미만일 때만 새 값으로 반환됩니다. 즉 발급 후 30일이 지난 시점부터 갱신을 요청하면 새 Refresh Token이 함께 내려옵니다.새 값이 포함된 경우 반드시 안전한 저장소에 즉시 갱신하여 저장하세요. 저장을 놓치면 60일 후 기존 Refresh Token이 만료되면서 사용자가 다시 인가를 받아야 합니다.
6. 연동 해제
연동을 끊는 경로는 두 가지입니다. 사용자가 모두싸인에서 직접 끊을 수도 있고, 서비스에서 API로 토큰을 무효화할 수도 있습니다.
사용자가 모두싸인에서 직접 해제하기
사용자는 모두싸인의 계정 설정 › 외부 서비스 연동에서 연결된 앱 목록을 확인하고 직접 연결을 끊을 수 있습니다. 워크스페이스를 잘못 선택해 다시 연결해야 할 때도 이 화면을 사용합니다.
이 화면에서는 연결된 워크스페이스, 연결한 날짜, 허용한 접근 범위를 확인할 수 있습니다. 연결 끊기를 누르면 해당 앱은 더 이상 이 워크스페이스에 접근할 수 없습니다.
서비스에서 API로 해제하기
사용자가 서비스 쪽에서 연동을 해제하거나 보안 이슈가 발생한 경우, 토큰 발급 취소 API로 즉시 토큰을 무효화하세요.
POST https://api.modusign.co.kr/oauth/token/revoke
| 파라미터 | 필수 여부 | 설명 |
|---|---|---|
client_id | ✅ | 애플리케이션 clientId |
client_secret | ✅ | 애플리케이션 clientSecret |
token | ✅ | 삭제할 access_token 또는 refresh_token |
curl --request POST \
--url https://api.modusign.co.kr/oauth/token/revoke \
--header 'Content-Type: application/json' \
--data '{
"client_id": "CLIENT-ID",
"client_secret": "CLIENT-SECRET",
"token": "ACCESS-OR-REFRESH-TOKEN"
}'const fetch = require('node-fetch');
const response = await fetch('https://api.modusign.co.kr/oauth/token/revoke', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
client_id: 'CLIENT-ID',
client_secret: 'CLIENT-SECRET',
token: 'ACCESS-OR-REFRESH-TOKEN'
})
});
console.log(response.status); // 204성공 시 **HTTP 204 No Content**가 반환되며 응답 바디는 없습니다.
해제 시 두 토큰을 모두 무효화하세요사용자가 연동을 해제할 때는
access_token과refresh_token을 모두 revoke 처리하세요.refresh_token이 탈취된 경우에도 즉시 revoke하여 추가 피해를 방지하세요.
7. 토큰 유효 기간 요약
| 토큰 | 유효 기간 | 갱신 조건 |
|---|---|---|
access_token | 30분 | refresh_token으로 언제든 재발급 가능 |
refresh_token | 60일 | 잔여 유효기간이 30일 미만인 상태에서 재발급을 요청하면 새 값으로 함께 반환 |
8. 자주 묻는 질문
FAQ
연결한 워크스페이스를 나중에 바꿀 수 있나요?
인가받은 연결의 워크스페이스를 직접 변경할 수는 없습니다. 모두싸인의 계정 설정 › 외부 서비스 연동에서 해당 앱의 연결을 끊은 뒤, 다시 인가 과정을 거치며 원하는 워크스페이스를 선택하세요.
워크스페이스 목록을 API로 조회하거나 새로 만들 수 있나요?
현재 공개된 API에는 워크스페이스 목록 조회·생성 기능이 없습니다. 워크스페이스 선택은 인가 페이지에서 사용자가 직접 수행합니다.
연결 후 API 호출이 실패합니다.
여러 원인이 있을 수 있지만, 인가는 정상적으로 끝났는데 문서 생성 등에서 오류가 난다면 요금제가 활성화되지 않은 워크스페이스로 연결되었을 가능성을 먼저 확인하세요.
- 모두싸인의 계정 설정 › 외부 서비스 연동에서 해당 앱의
연결된 워크스페이스를 확인합니다. - 의도한 워크스페이스가 아니라면
연결 끊기후 다시 연동하며 올바른 워크스페이스를 선택하세요.
접근 범위를 일부만 허용하도록 할 수 있나요?
항목에 따라 다릅니다. 필수로 표시된 항목은 사용자가 해제할 수 없고, 선택 항목만 끌 수 있습니다. 어떤 항목이 필수인지는 앱에 설정된 요청 범위에 따라 결정됩니다.
사용자가 선택 항목을 끈 채로 연결하면 해당 권한이 필요한 API 호출은 실패합니다. 서비스 동작에 반드시 필요한 권한이라면 앱 등록 시 필수로 지정해 두세요.
사용자가 이미 다른 계정으로 로그인되어 있습니다.
인가 페이지의 다른 계정으로 로그인을 사용하거나, 아래 URL로 로그아웃 처리한 뒤 다시 인가 요청을 보내세요.
https://app.modusign.co.kr/signout?redirectTo=${encodeURIComponent('https://modusign.co.kr')}
더 자세한 API 내용은 API References에서 확인하세요!토큰 발급 및 재발급 · 토큰 발급 취소 · 문서 리스트 조회 의 자세한 내용을 확인하세요.
유의사항
clientSecret은 반드시 서버사이드에서만 처리하세요. 브라우저·모바일 앱에 포함하면 안 됩니다.state값은 인가 요청과 콜백에서 반드시 대조해 CSRF 공격을 방어하세요.- OAuth 연결은 사용자가 선택한 워크스페이스 하나에만 적용됩니다. 워크스페이스를 바꾸려면 연결을 끊고 다시 인가받아야 합니다.
- 요금제가 활성화되지 않은 워크스페이스로 연결하면 인가는 성공해도 이후 API 호출이 실패할 수 있습니다. 연동 안내 화면에서 워크스페이스 선택에 대한 안내를 함께 제공하세요.
- 새로 발급받은
refresh_token은 즉시 저장소에 반영하세요. 갱신을 놓치면 사용자가 다시 인가해야 합니다.
Updated 5 days ago
