OpenID Connect (OIDC)
- OAuth 2.0을 기반으로 하는 인증 프로토콜
- 사용자의 신원을 확인하고 사용자 정보를 안전하게 교환할 수 있도록 설계됐다.
- OIDC는 사용자 로그인 및 Single Sign-On (SSO)을 구현하는 데 매우 유용하며, 웹 애플리케이션, 모바일 애플리케이션, API 서버 등 다양한 클라이언트에서 널리 사용된다.
주요 구성 요소
- End-User (사용자): 인증을 요청하는 실제 사용자
- Relying Party (RP): 사용자 인증과 사용자 정보를 필요로 하는 애플리케이션 또는 서비스
- OpenID Provider (OP): 사용자를 인증하고, 인증된 사용자 정보를 제공하는 서비스 제공자(ex. Google, Facebook, Microsoft 등)
- ID Token: 사용자에 대한 인증 정보 및 기타 클레임을 포함하는 JWT (JSON Web Token)
주요 엔드포인트
- Authorization Endpoint: 사용자가 로그인 페이지를 통해 인증하고, 인증 코드를 얻기 위해 사용하는 엔드포인트
- Token Endpoint: RP가 권한 부여 코드를 사용하여 ID 토큰과 액세스 토큰을 요청하는 엔드포인트
- UserInfo Endpoint: RP가 액세스 토큰을 사용하여 사용자 정보를 요청하는 엔드포인트
OpenID Connect 흐름
OpenID Connect는 주로 다음과 같은 흐름으로 동작한다.

1. 인증 요청
클라이언트(애플리케이션 또는 서비스)가 OpenID Provider에 사용자의 인증을 요청한다.
이때 클라이언트는 response_type, client_id, redirect_uri, scope 등의 파라미터를 포함한 요청을 전송한다.
2. 인증 및 권한 부여
OpenID Provider는 사용자가 인증 페이지에서 로그인하도록 안내한다.
사용자가 성공적으로 로그인하면, OpenID Provider는 클라이언트에게 권한 부여 코드 (Authorization Code)를 반환한다.
3. 토큰 요청
클라이언트는 권한 부여 코드를 사용하여 OpenID Provider의 토큰 엔드포인트에 ID 토큰과 액세스 토큰을 요청한다.
이 요청에는 grant_type, code, redirect_uri, client_id, client_secret 등의 파라미터가 포함된다.
4. 토큰 발급
OpenID Provider는 클라이언트에게 ID 토큰과 액세스 토큰을 반환한다.
ID 토큰은 사용자의 인증 정보를 포함하고 있으며, 액세스 토큰은 UserInfo 엔드포인트에 사용자 정보를 요청하는 데 사용된다.
5. 사용자 정보 요청
클라이언트는 액세스 토큰을 사용하여 OpenID Provider의 UserInfo 엔드포인트에 사용자 정보를 요청한다.
OpenID Provider는 사용자 프로필 정보를 JSON 형식으로 반환한다.
예시 코드 (Python, Flask, Authlib 사용)
OpenID Connect를 구현하는 예시 코드를 Flask와 Authlib 라이브러리를 사용하여 작성해 봤다.
설치
pip install Flask Authlib
코드[python]
from flask import Flask, redirect, url_for, session
from authlib.integrations.flask_client import OAuth
from authlib.oidc.core import UserInfo
app = Flask(__name__)
app.secret_key = 'random_secret_key'
oauth = OAuth(app)
# OpenID Connect Provider 설정 (예: Google)
oauth.register(
name='google',
client_id='YOUR_GOOGLE_CLIENT_ID',
client_secret='YOUR_GOOGLE_CLIENT_SECRET',
server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
client_kwargs={
'scope': 'openid profile email',
}
)
@app.route('/')
def homepage():
user = session.get('user')
if user:
return f'Hello, {user["name"]}!'
return 'Welcome to the OpenID Connect demo. <a href="/login">Login</a>'
@app.route('/login')
def login():
redirect_uri = url_for('auth', _external=True)
return oauth.google.authorize_redirect(redirect_uri)
@app.route('/auth')
def auth():
token = oauth.google.authorize_access_token()
user_info = oauth.google.parse_id_token(token)
session['user'] = {
'name': user_info['name'],
'email': user_info['email']
}
return redirect('/')
@app.route('/logout')
def logout():
session.pop('user', None)
return redirect('/')
if __name__ == '__main__':
app.run()
코드 설명
1. OAuth 설정
`oauth.register`를 사용하여 OpenID Provider를 등록한다.
이 예제에서는 Google을 사용하며, `client_id`와 `client_secret`을 설정한다.
`scope`는 요청할 권한을 지정하며, 여기서는 `openid`, `profile`, `email`을 요청한다.
2. 홈페이지 라우트
`/` 라우트에서 사용자가 로그인되어 있는지 확인한다.
로그인된 경우 사용자의 이름을 표시하고, 그렇지 않은 경우 로그인 링크를 제공한다.
3. 로그인 라우트
`/login` 라우트에서 OpenID Provider의 인증 페이지로 리디렉션한다.
`redirect_uri`는 인증 후 돌아올 콜백 URL이다.
4. 인증 콜백 라우트
`/auth` 라우트에서 OpenID Provider로부터 인증 결과를 수신한다.
`authorize_access_token`을 사용하여 토큰을 교환하고, `parse_id_token`을 사용하여 ID 토큰을 파싱한다.
사용자 정보를 세션에 저장한다.
5. 로그아웃 라우트
`/logout` 라우트에서 세션을 정리하여 로그아웃을 수행한다.
보안 고려 사항
OpenID Connect를 사용할 때는 다음과 같은 보안 고려 사항을 준수해야 한다.
1. HTTPS 사용: 모든 통신은 HTTPS를 통해 암호화되어야 한다.
2. 비밀 키 관리: `client_secret` 등 비밀 정보는 안전하게 관리되어야 한다.
3. 토큰 검증: 수신한 ID 토큰의 서명과 만료 시간을 검증해야 한다.
4. CSRF 방지: CSRF 공격을 방지하기 위해 상태 파라미터를 사용해야 한다.
5. 최소 권한 원칙: 필요한 최소한의 권한만 요청하도록 설정한다.
정리
OpenID Connect는 OAuth 2.0을 확장하여 인증과 사용자 정보 제공을 위한 표준을 정의함으로써, 다양한 애플리케이션에서 안전하고 편리한 사용자 인증을 구현할 수 있게 한다.
이를 통해 사용자는 여러 서비스에서 동일한 인증 정보를 사용할 수 있으며, 개발자는 표준화된 프로토콜을 사용하여 인증 기능을 쉽게 구현할 수 있다.
'CS' 카테고리의 다른 글
APNs(Apple Push Notification Service) (0) | 2024.08.20 |
---|---|
FCM(Firebase Cloud Messaging) (0) | 2024.08.17 |
PCI DSS (0) | 2024.07.31 |
데이터 모델링(Data Modeling) (3) | 2024.07.25 |
OAuth 2.0 개념 (0) | 2024.07.09 |