Cognito 서비스에서 User Pool과 Identity Pool 에서 개별적으로 OIDC(Open Identity Connect) 기능과 OAuth2 를 제공하고 있다. 하지만 각자 사용하는 용도와 목적의 차이가 있기에 이를 정리한다.
1. Conito User Pool with OAuth2.0
OAuth2 는 인가를 위한 프레임워크로 사용자의 자격인증을 공유하지 않으면서 권한을 부여할 수 있는 방식이다.
이를 인증하는 방법은 여러가지가 있으나 기본적으로 Code 를 기반으로 인증을 수행하는 방법이 범용적으로 많이 사용된다.
여러 인증 방식은 아래의 링크를 확인하자
Understanding Amazon Cognito user pool OAuth 2.0 grants | Front-End Web & Mobile
Understanding Amazon Cognito user pool OAuth 2.0 grants | Amazon Web Services
In addition to using the Amazon Cognito-specific user APIs to authenticate users, Amazon Cognito user pools also support the OAuth 2.0 authorization framework for authenticating users. After you configure a domain for the user pool, Amazon Cognito automati
aws.amazon.com
OAuth의 인증이 완료되면 Client에 Token을 발행하고 Token을 target server에 함께 전달하여 API를 요청을 한다.
Token을 받은 API 서버는 token을 OAuth 서버로부터 validation 을 하며 확인이 끝나면 token 의 'scope' claim 의 정보를 확인하여 요청에 대한 권한이 있는지를 판별하도록 한다.

Cognito User Pool은 OAuth2의 서버의 역할을 하여 인증된 사용자에게 지정된 권한의 정보를 token에 넣어서 전달하게 된다. Custom Scope를 설정하기 위해서는 Cognito AWS Management Console 에서 User Pool의 설정을 들어가 앱통합 탭에 있는 리소스 서버를 생성하고 필요한 범위를 생성 관리할 수 있다.


2. 코드 구현 for using User Pool with OAuth2.0
Client 프로그램은 사용자 인증을 통해 accessToken을 발급받는다. 이 token에 대한 JwtSecurityTokenHandler를 통해 validation 을 수행하고 내부 내용을 읽는다.
Client 는 jwt 에 포함되어 있는 'scope' 정보를 바탕으로 사용자의 요청을 수행할지 아닐지를 판단한다.
다만, 원하는 scope 정보를 포한 된 token을 얻기 위해서는 InitiateAuthRequest 에 scope property 를 지정해줘야 한다.
하지만, WPF 의 경우에는 이를 지원하지 않고 있다.
따라서 WPF를 이용하기 위해서는 복잡한 과정이 필요하다.
위에서 언급한 Code 기반의 인증 방식을 Web browser 통해 수행해야 한다.
이때 WebBrowser 를 WPF의 기본 browser가 아닌 WebView2 nuget package에서 설치하여 사용해야 한다.
PM> Install-Package Microsoft.Web.WebView2
A. WebBrowser 를 통해 Hosting UI에 접근하여 인증을 요청한다.
var queryParams = HttpUtility.ParseQueryString(string.Empty);
queryParams["client_id"] = "my_userpool_client_id";
queryParams["response_type"] = "code";
queryParams["scope"] = "aws.cognito.signin.user.admin email https://localhost/api/read/id https://localhost/api/read/name openid phone profile";
queryParams["redirect_uri"] = "myapp://callback";
var url = "https://{domain}.auth.{region}.amazoncognito.com/login?" + queryParams.ToString();
webView.CoreWebView2.Navigate(url);
B. 인증 요청에 전달한 redirect_uri 를 통해 code를 획득한다.
private async void WebView_NavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs e)
{
if (e.Uri.StartsWith("myapp://callback"))
{
e.Cancel = true;
var queryParameters = HttpUtility.ParseQueryString(new Uri(e.Uri).Query);
var authorizationCode = queryParameters["code"];
// Exchange the authorization code for tokens
// Close the WebView or navigate to a different page in your WPF application
}
}
C. 받은 Code를 Token으로 교환한다.
여기에서 또다른 어려움이 발생한다. WPF SDK에서는 AuthFlowType 에서 Authroization_Code를 지원하지 않는다.
따라서 Custom_Auth 를 이용하여 Code를 Token으로 받아야 한다.
public async Task<string> InitiateAuthFromCodeAsync(string authorizationCode)
{
var provider = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials(), region);
var request = new InitiateAuthRequest
{
AuthFlow = AuthFlowType.CUSTOM_AUTH,
ClientId = clientID,
AuthParameters = new Dictionary<string, string>
{
{ "code", authorizationCode },
{ "redirect_uri", "myapp://token" }
}
};
var response = await provider.InitiateAuthAsync(request);
return response.AuthenticationResult.AccessToken;
}
D. 그다음 장볍은 Custom_Auth 에 대한 Lambda Trigger를 구성해야한다. Custom 이므로 결국엔 Trigger에 의해 제어가 되는 것 같다. 여기에서 막혔다.
위의 Token을 얻는 부분을 제외하고 token을 통해서 scope정보를 얻을 수 있다고 가정하고 다음을 진행해 본다.
아래는 token을 UserPool 에 요청하여 signing 공개 키를 얻어 token 을 발행한 validation 을 수행한다
public void CheckOAuthScope()
{
// Fetch JWKS from the Cognito User Pool
HttpClient httpClient = new HttpClient();
HttpResponseMessage response = httpClient.GetAsync(jwksUrl).Result;
string jwksJson = response.Content.ReadAsStringAsync().Result;
JObject jwks = JObject.Parse(jwksJson);
IList<JsonWebKey> signingKeys = jwks["keys"].Select(x => new JsonWebKey(x.ToString())).ToList();
// Validate the JWT access token and extract the granted scopes
bool isValidToken = false;
List<string> grantedScopes = null;
try
{
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "https://cognito-idp.ap-northeast-2.amazonaws.com/ap-northeast-2_ZTXeBgRcW",
ValidateAudience = false,
ValidAudiences = new []{ "29n1ttfjveiqsst88jcqgha8ep" },
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(5),
ValidateIssuerSigningKey = true,
IssuerSigningKeys = signingKeys,
};
var jwtHandler = new JwtSecurityTokenHandler();
SecurityToken validatedToken;
var jwtToken = jwtHandler.ReadJwtToken(AccessToken);
jwtHandler.ValidateToken(AccessToken, tokenValidationParameters, out validatedToken);
// 참고로 WPF 에서는 InitiateSrpAuthRequest에서 Scope를 지정하여 인증을 진행할 수 없다.
// 구현이 필요한경우 WebBrowser를 구성하고 Hosting UI url을 통해서 접속하고 redirect code값을
string grantedScopesString = jwtToken.Claims.FirstOrDefault(c => c.Type == "scope")?.Value;
grantedScopes = grantedScopesString?.Split(' ').ToList() ?? new List<string>();
isValidToken = true;
}
catch (Exception ex)
{
Console.WriteLine($"Token validation failed: {ex.Message}");
}
if (isValidToken)
{
Console.WriteLine("Access token is valid.");
Console.WriteLine($"Granted scopes: {string.Join(", ", grantedScopes)}");
}
else
{
Console.WriteLine("Access token is invalid.");
}
}
Cognito 서비스에서 User Pool과 Identity Pool 에서 개별적으로 OIDC(Open Identity Connect) 기능과 OAuth2 를 제공하고 있다. 하지만 각자 사용하는 용도와 목적의 차이가 있기에 이를 정리한다.
1. Conito User Pool with OAuth2.0
OAuth2 는 인가를 위한 프레임워크로 사용자의 자격인증을 공유하지 않으면서 권한을 부여할 수 있는 방식이다.
이를 인증하는 방법은 여러가지가 있으나 기본적으로 Code 를 기반으로 인증을 수행하는 방법이 범용적으로 많이 사용된다.
여러 인증 방식은 아래의 링크를 확인하자
Understanding Amazon Cognito user pool OAuth 2.0 grants | Front-End Web & Mobile
Understanding Amazon Cognito user pool OAuth 2.0 grants | Amazon Web Services
In addition to using the Amazon Cognito-specific user APIs to authenticate users, Amazon Cognito user pools also support the OAuth 2.0 authorization framework for authenticating users. After you configure a domain for the user pool, Amazon Cognito automati
aws.amazon.com
OAuth의 인증이 완료되면 Client에 Token을 발행하고 Token을 target server에 함께 전달하여 API를 요청을 한다.
Token을 받은 API 서버는 token을 OAuth 서버로부터 validation 을 하며 확인이 끝나면 token 의 'scope' claim 의 정보를 확인하여 요청에 대한 권한이 있는지를 판별하도록 한다.

Cognito User Pool은 OAuth2의 서버의 역할을 하여 인증된 사용자에게 지정된 권한의 정보를 token에 넣어서 전달하게 된다. Custom Scope를 설정하기 위해서는 Cognito AWS Management Console 에서 User Pool의 설정을 들어가 앱통합 탭에 있는 리소스 서버를 생성하고 필요한 범위를 생성 관리할 수 있다.


2. 코드 구현 for using User Pool with OAuth2.0
Client 프로그램은 사용자 인증을 통해 accessToken을 발급받는다. 이 token에 대한 JwtSecurityTokenHandler를 통해 validation 을 수행하고 내부 내용을 읽는다.
Client 는 jwt 에 포함되어 있는 'scope' 정보를 바탕으로 사용자의 요청을 수행할지 아닐지를 판단한다.
다만, 원하는 scope 정보를 포한 된 token을 얻기 위해서는 InitiateAuthRequest 에 scope property 를 지정해줘야 한다.
하지만, WPF 의 경우에는 이를 지원하지 않고 있다.
따라서 WPF를 이용하기 위해서는 복잡한 과정이 필요하다.
위에서 언급한 Code 기반의 인증 방식을 Web browser 통해 수행해야 한다.
이때 WebBrowser 를 WPF의 기본 browser가 아닌 WebView2 nuget package에서 설치하여 사용해야 한다.
PM> Install-Package Microsoft.Web.WebView2
A. WebBrowser 를 통해 Hosting UI에 접근하여 인증을 요청한다.
var queryParams = HttpUtility.ParseQueryString(string.Empty);
queryParams["client_id"] = "my_userpool_client_id";
queryParams["response_type"] = "code";
queryParams["scope"] = "aws.cognito.signin.user.admin email https://localhost/api/read/id https://localhost/api/read/name openid phone profile";
queryParams["redirect_uri"] = "myapp://callback";
var url = "https://{domain}.auth.{region}.amazoncognito.com/login?" + queryParams.ToString();
webView.CoreWebView2.Navigate(url);
B. 인증 요청에 전달한 redirect_uri 를 통해 code를 획득한다.
private async void WebView_NavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs e)
{
if (e.Uri.StartsWith("myapp://callback"))
{
e.Cancel = true;
var queryParameters = HttpUtility.ParseQueryString(new Uri(e.Uri).Query);
var authorizationCode = queryParameters["code"];
// Exchange the authorization code for tokens
// Close the WebView or navigate to a different page in your WPF application
}
}
C. 받은 Code를 Token으로 교환한다.
여기에서 또다른 어려움이 발생한다. WPF SDK에서는 AuthFlowType 에서 Authroization_Code를 지원하지 않는다.
따라서 Custom_Auth 를 이용하여 Code를 Token으로 받아야 한다.
public async Task<string> InitiateAuthFromCodeAsync(string authorizationCode)
{
var provider = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials(), region);
var request = new InitiateAuthRequest
{
AuthFlow = AuthFlowType.CUSTOM_AUTH,
ClientId = clientID,
AuthParameters = new Dictionary<string, string>
{
{ "code", authorizationCode },
{ "redirect_uri", "myapp://token" }
}
};
var response = await provider.InitiateAuthAsync(request);
return response.AuthenticationResult.AccessToken;
}
D. 그다음 장볍은 Custom_Auth 에 대한 Lambda Trigger를 구성해야한다. Custom 이므로 결국엔 Trigger에 의해 제어가 되는 것 같다. 여기에서 막혔다.
위의 Token을 얻는 부분을 제외하고 token을 통해서 scope정보를 얻을 수 있다고 가정하고 다음을 진행해 본다.
아래는 token을 UserPool 에 요청하여 signing 공개 키를 얻어 token 을 발행한 validation 을 수행한다
public void CheckOAuthScope()
{
// Fetch JWKS from the Cognito User Pool
HttpClient httpClient = new HttpClient();
HttpResponseMessage response = httpClient.GetAsync(jwksUrl).Result;
string jwksJson = response.Content.ReadAsStringAsync().Result;
JObject jwks = JObject.Parse(jwksJson);
IList<JsonWebKey> signingKeys = jwks["keys"].Select(x => new JsonWebKey(x.ToString())).ToList();
// Validate the JWT access token and extract the granted scopes
bool isValidToken = false;
List<string> grantedScopes = null;
try
{
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "https://cognito-idp.ap-northeast-2.amazonaws.com/ap-northeast-2_ZTXeBgRcW",
ValidateAudience = false,
ValidAudiences = new []{ "29n1ttfjveiqsst88jcqgha8ep" },
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(5),
ValidateIssuerSigningKey = true,
IssuerSigningKeys = signingKeys,
};
var jwtHandler = new JwtSecurityTokenHandler();
SecurityToken validatedToken;
var jwtToken = jwtHandler.ReadJwtToken(AccessToken);
jwtHandler.ValidateToken(AccessToken, tokenValidationParameters, out validatedToken);
// 참고로 WPF 에서는 InitiateSrpAuthRequest에서 Scope를 지정하여 인증을 진행할 수 없다.
// 구현이 필요한경우 WebBrowser를 구성하고 Hosting UI url을 통해서 접속하고 redirect code값을
string grantedScopesString = jwtToken.Claims.FirstOrDefault(c => c.Type == "scope")?.Value;
grantedScopes = grantedScopesString?.Split(' ').ToList() ?? new List<string>();
isValidToken = true;
}
catch (Exception ex)
{
Console.WriteLine($"Token validation failed: {ex.Message}");
}
if (isValidToken)
{
Console.WriteLine("Access token is valid.");
Console.WriteLine($"Granted scopes: {string.Join(", ", grantedScopes)}");
}
else
{
Console.WriteLine("Access token is invalid.");
}
}