不使用托管 UI 的 AWS Cognito 授权代码授予流程
AWS Cognito Authorization code grant flow without using the hosted UI
在没有托管 UI 的情况下使用 AWS 的 Cognito,给定用户名和密码我想在不使用托管 ui.
的情况下获得授权码授予
这可能吗?我正在编写自己的注册、登录表格,但似乎找不到关于此主题的文档。
目前我可以使用 AWS.CognitoIdentityServiceProvider 和 initiateAuth 函数来交换令牌的用户名密码,但我不想 return 重定向中的那些令牌 URL,我宁愿return授权码授予,可兑换令牌。
那么我如何使用 initiateAuth 接收授权码而不是令牌。
更新:使用下面的正确答案,这就是我最终在节点中完成的方式。
const base64url = require('base64url');
const crypto = require('crypto');
const request = require('request');
const querystring = require ('querystring');
function generateCodeVerifierHash(code_verifier) {
return crypto.createHmac('SHA256', code_verifier)
.digest('base64');
}
function generateCodeVerifier() {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._`-";
for (var i = 0; i < 64; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return base64url.encode(text);
}
var CLIENT_ID="Your Client Id";
var CLIENT_SECRET="Your Client Secret";
var RESPONSE_TYPE="code";
var REDIRECT_URI= encodeURIComponent("Your Redirect Url");
var SCOPE="openid";
var AUTH_DOMAIN= "Your Cognito Auth Domain";
var USERNAME="User's Username";
var PASSWORD="User's Password";
var CODE_CHALLENGE_METHOD="S256";
// Challenge
var code_verifier = generateCodeVerifier();
var code_challenge = generateCodeVerifierHash(code_verifier);
// Get CSRF token from /oauth2/authorize endpoint
var csrfRequestUrl = `https://${AUTH_DOMAIN}/oauth2/authorize?response_type=${RESPONSE_TYPE}&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&scope=${SCOPE}&code_challenge_method=${CODE_CHALLENGE_METHOD}&code_challenge=${code_challenge}`;
// Post CSRF Token and username/password to /login endpoint
var codeRequestUrl = `https://${AUTH_DOMAIN}/login?response_type=${RESPONSE_TYPE}&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}`;
request.get(csrfRequestUrl, (err, res, body) => {
var XSRFTOKEN = res.headers['set-cookie'].filter( (header) => header.substring(0,10) == 'XSRF-TOKEN')[0];
form = {
'_csrf': `${XSRFTOKEN.split(';')[0].split('=')[1]}`,
'username': `${USERNAME}`,
'password': `${PASSWORD}`,
}
var formData = querystring.stringify(form);
var contentLength = formData.length;
request({
headers: {
'Content-Length': contentLength,
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': `${XSRFTOKEN}`,
},
uri: codeRequestUrl,
body: formData,
method: 'POST'
}, function (err, res, body) {
var authorizationCodeGrant = res.headers.location.split('=')[1];
console.log(authorizationCodeGrant);
});
});
没有办法通过使用 initiateAuth 和 respondToAuthChallenge 来做到这一点,因为这只涉及针对您的用户池的身份验证,最终结果将是您将获得令牌。
但是,完全可以通过代码与授权、令牌和登录端点进行交互。如果您查看以下 shell 脚本代码,您将了解需要传递给端点的信息:
#!/usr/bin/env bash
#===============================================================================
# SET AUTH DOMAIN
#===============================================================================
AUTH_DOMAIN="MY-DOMAIN.auth.REGION.amazoncognito.com"
#===============================================================================
# AUTH CODE/IMPLICIT GRANTS, WITHOUT PKCE, WITHOUT CLIENT SECRET
#===============================================================================
## Set constants ##
CLIENT_ID="USER_POOL_CLIENT_ID"
RESPONSE_TYPE="code"
#RESPONSE_TYPE="token"
REDIRECT_URI="https://example.com/"
SCOPE="openid"
USERNAME="testuser"
PASSWORD="testpassword"
## Get CSRF token and LOGIN URL from /oauth2/authorize endpoint ##
curl_response="$(
curl -qv "https://${AUTH_DOMAIN}/oauth2/authorize?response_type=${RESPONSE_TYPE}&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&scope=${SCOPE}" 2>&1
)"
curl_redirect="$(printf "%s" "$curl_response" \
| awk '/^< Location: / {
gsub(/\r/, ""); # Remove carriage returns
print ; # Print redirect URL
}')"
csrf_token="$(printf "%s" "$curl_response" \
| awk '/^< Set-Cookie:/ {
gsub(/^XSRF-TOKEN=|;$/, "", ); # Remove cookie name and semi-colon
print ; # Print cookie value
}')"
## Get auth code or tokens from /login endpoint ##
curl_response="$(
curl -qv "$curl_redirect" \
-H "Cookie: XSRF-TOKEN=${csrf_token}; Path=/; Secure; HttpOnly" \
-d "_csrf=${csrf_token}" \
-d "username=${USERNAME}" \
-d "password=${PASSWORD}" 2>&1
)"
curl_redirect="$(printf "%s" "$curl_response" \
| awk '/^< Location: / {
gsub(/\r/, ""); # Remove carriage returns
print ; # Print redirect URL
}')"
auth_code="$(printf "%s" "$curl_redirect" \
| awk '{
sub(/.*code=/, ""); # Remove everything before auth code
print; # Print auth code
}')"
## Get tokens from /oauth2/token endpoint ##
GRANT_TYPE="authorization_code"
curl "https://${AUTH_DOMAIN}/oauth2/token" \
-d "grant_type=${GRANT_TYPE}" \
-d "client_id=${CLIENT_ID}" \
-d "code=${auth_code}" \
-d "redirect_uri=${REDIRECT_URI}"
#===============================================================================
# AUTH CODE/IMPLICIT GRANTS, WITH PKCE, WITH CLIENT SECRET
#===============================================================================
## Set constants ##
CLIENT_ID="USER_POOL_CLIENT_ID"
CLIENT_SECRET="USER_POOL_CLIENT_SECRET"
RESPONSE_TYPE="code"
#RESPONSE_TYPE="token"
REDIRECT_URI="https://example.com/"
SCOPE="openid"
USERNAME="testuser"
PASSWORD="testpassword"
## Create a code_verifier and code_challenge ##
CODE_CHALLENGE_METHOD="S256"
# code_verifier = random, 64-char string consisting of chars between letters,
# numbers, periods, underscores, tildes, or hyphens; the string
# is then base64-url encoded
code_verifier="$(cat /dev/urandom \
| tr -dc 'a-zA-Z0-9._~-' \
| fold -w 64 \
| head -n 1 \
| base64 \
| tr '+/' '-_' \
| tr -d '='
)"
# code_challenge = SHA-256 hash of the code_verifier; it is then base64-url
# encoded
code_challenge="$(printf "$code_verifier" \
| openssl dgst -sha256 -binary \
| base64 \
| tr '+/' '-_' \
| tr -d '='
)"
## Get CSRF token from /oauth2/authorize endpoint ##
curl_response="$(
curl -qv "https://${AUTH_DOMAIN}/oauth2/authorize?response_type=${RESPONSE_TYPE}&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&scope=${SCOPE}&code_challenge_method=${CODE_CHALLENGE_METHOD}&code_challenge=${code_challenge}" 2>&1
)"
curl_redirect="$(printf "%s" "$curl_response" \
| awk '/^< Location: / {
gsub(/\r/, ""); # Remove carriage returns
print ; # Print redirect URL
}')"
csrf_token="$(printf "%s" "$curl_response" \
| awk '/^< Set-Cookie:/ {
gsub(/^XSRF-TOKEN=|;$/, "", ); # Remove cookie name and semi-colon
print ; # Print cookie value
}')"
## Get auth code or tokens from /login endpoint ##
curl_response="$(
curl -qv "$curl_redirect" \
-H "Cookie: XSRF-TOKEN=${csrf_token}; Path=/; Secure; HttpOnly" \
-d "_csrf=${csrf_token}" \
-d "username=${USERNAME}" \
-d "password=${PASSWORD}" 2>&1
)"
curl_redirect="$(printf "%s" "$curl_response" \
| awk '/^< Location: / {
gsub(/\r/, ""); # Remove carriage returns
print ; # Print redirect URL
}'
)"
auth_code="$(printf "%s" "$curl_redirect" \
| awk '{
sub(/.*code=/, ""); # Remove everything before auth code
print; # Print auth code
}')"
## Get tokens from /oauth2/token endpoint ##
authorization="$(printf "${CLIENT_ID}:${CLIENT_SECRET}" \
| base64 \
| tr -d "\n" # Remove line feed
)"
GRANT_TYPE="authorization_code"
curl "https://${AUTH_DOMAIN}/oauth2/token" \
-H "Authorization: Basic ${authorization}" \
-d "grant_type=${GRANT_TYPE}" \
-d "client_id=${CLIENT_ID}" \
-d "code=${auth_code}" \
-d "redirect_uri=${REDIRECT_URI}" \
-d "code_verifier=${code_verifier}"
#===============================================================================
# CLIENT CREDENTIALS GRANT
#===============================================================================
## Set constants ##
CLIENT_ID="USER_POOL_CLIENT_ID"
CLIENT_SECRET="USER_POOL_CLIENT_SECRET"
GRANT_TYPE="client_credentials"
## Get access token from /oauth2/token endpoint ##
authorization="$(printf "${CLIENT_ID}:${CLIENT_SECRET}" \
| base64 \
| tr -d "\n" # Remove line feed
)"
curl "https://${AUTH_DOMAIN}/oauth2/token" \
-H "Authorization: Basic ${authorization}" \
-d "grant_type=${GRANT_TYPE}"
#===============================================================================
# LOGOUT
#===============================================================================
## Set constants ##
CLIENT_ID="USER_POOL_CLIENT_ID"
REDIRECT_URI="https://example.com/"
## Hit /logout endpoint ##
curl -v "https://${AUTH_DOMAIN}/logout?client_id=${CLIENT_ID}&logout_uri=${REDIRECT_URI}"
在没有托管 UI 的情况下使用 AWS 的 Cognito,给定用户名和密码我想在不使用托管 ui.
的情况下获得授权码授予这可能吗?我正在编写自己的注册、登录表格,但似乎找不到关于此主题的文档。
目前我可以使用 AWS.CognitoIdentityServiceProvider 和 initiateAuth 函数来交换令牌的用户名密码,但我不想 return 重定向中的那些令牌 URL,我宁愿return授权码授予,可兑换令牌。
那么我如何使用 initiateAuth 接收授权码而不是令牌。
更新:使用下面的正确答案,这就是我最终在节点中完成的方式。
const base64url = require('base64url');
const crypto = require('crypto');
const request = require('request');
const querystring = require ('querystring');
function generateCodeVerifierHash(code_verifier) {
return crypto.createHmac('SHA256', code_verifier)
.digest('base64');
}
function generateCodeVerifier() {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._`-";
for (var i = 0; i < 64; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return base64url.encode(text);
}
var CLIENT_ID="Your Client Id";
var CLIENT_SECRET="Your Client Secret";
var RESPONSE_TYPE="code";
var REDIRECT_URI= encodeURIComponent("Your Redirect Url");
var SCOPE="openid";
var AUTH_DOMAIN= "Your Cognito Auth Domain";
var USERNAME="User's Username";
var PASSWORD="User's Password";
var CODE_CHALLENGE_METHOD="S256";
// Challenge
var code_verifier = generateCodeVerifier();
var code_challenge = generateCodeVerifierHash(code_verifier);
// Get CSRF token from /oauth2/authorize endpoint
var csrfRequestUrl = `https://${AUTH_DOMAIN}/oauth2/authorize?response_type=${RESPONSE_TYPE}&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&scope=${SCOPE}&code_challenge_method=${CODE_CHALLENGE_METHOD}&code_challenge=${code_challenge}`;
// Post CSRF Token and username/password to /login endpoint
var codeRequestUrl = `https://${AUTH_DOMAIN}/login?response_type=${RESPONSE_TYPE}&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}`;
request.get(csrfRequestUrl, (err, res, body) => {
var XSRFTOKEN = res.headers['set-cookie'].filter( (header) => header.substring(0,10) == 'XSRF-TOKEN')[0];
form = {
'_csrf': `${XSRFTOKEN.split(';')[0].split('=')[1]}`,
'username': `${USERNAME}`,
'password': `${PASSWORD}`,
}
var formData = querystring.stringify(form);
var contentLength = formData.length;
request({
headers: {
'Content-Length': contentLength,
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': `${XSRFTOKEN}`,
},
uri: codeRequestUrl,
body: formData,
method: 'POST'
}, function (err, res, body) {
var authorizationCodeGrant = res.headers.location.split('=')[1];
console.log(authorizationCodeGrant);
});
});
没有办法通过使用 initiateAuth 和 respondToAuthChallenge 来做到这一点,因为这只涉及针对您的用户池的身份验证,最终结果将是您将获得令牌。
但是,完全可以通过代码与授权、令牌和登录端点进行交互。如果您查看以下 shell 脚本代码,您将了解需要传递给端点的信息:
#!/usr/bin/env bash
#===============================================================================
# SET AUTH DOMAIN
#===============================================================================
AUTH_DOMAIN="MY-DOMAIN.auth.REGION.amazoncognito.com"
#===============================================================================
# AUTH CODE/IMPLICIT GRANTS, WITHOUT PKCE, WITHOUT CLIENT SECRET
#===============================================================================
## Set constants ##
CLIENT_ID="USER_POOL_CLIENT_ID"
RESPONSE_TYPE="code"
#RESPONSE_TYPE="token"
REDIRECT_URI="https://example.com/"
SCOPE="openid"
USERNAME="testuser"
PASSWORD="testpassword"
## Get CSRF token and LOGIN URL from /oauth2/authorize endpoint ##
curl_response="$(
curl -qv "https://${AUTH_DOMAIN}/oauth2/authorize?response_type=${RESPONSE_TYPE}&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&scope=${SCOPE}" 2>&1
)"
curl_redirect="$(printf "%s" "$curl_response" \
| awk '/^< Location: / {
gsub(/\r/, ""); # Remove carriage returns
print ; # Print redirect URL
}')"
csrf_token="$(printf "%s" "$curl_response" \
| awk '/^< Set-Cookie:/ {
gsub(/^XSRF-TOKEN=|;$/, "", ); # Remove cookie name and semi-colon
print ; # Print cookie value
}')"
## Get auth code or tokens from /login endpoint ##
curl_response="$(
curl -qv "$curl_redirect" \
-H "Cookie: XSRF-TOKEN=${csrf_token}; Path=/; Secure; HttpOnly" \
-d "_csrf=${csrf_token}" \
-d "username=${USERNAME}" \
-d "password=${PASSWORD}" 2>&1
)"
curl_redirect="$(printf "%s" "$curl_response" \
| awk '/^< Location: / {
gsub(/\r/, ""); # Remove carriage returns
print ; # Print redirect URL
}')"
auth_code="$(printf "%s" "$curl_redirect" \
| awk '{
sub(/.*code=/, ""); # Remove everything before auth code
print; # Print auth code
}')"
## Get tokens from /oauth2/token endpoint ##
GRANT_TYPE="authorization_code"
curl "https://${AUTH_DOMAIN}/oauth2/token" \
-d "grant_type=${GRANT_TYPE}" \
-d "client_id=${CLIENT_ID}" \
-d "code=${auth_code}" \
-d "redirect_uri=${REDIRECT_URI}"
#===============================================================================
# AUTH CODE/IMPLICIT GRANTS, WITH PKCE, WITH CLIENT SECRET
#===============================================================================
## Set constants ##
CLIENT_ID="USER_POOL_CLIENT_ID"
CLIENT_SECRET="USER_POOL_CLIENT_SECRET"
RESPONSE_TYPE="code"
#RESPONSE_TYPE="token"
REDIRECT_URI="https://example.com/"
SCOPE="openid"
USERNAME="testuser"
PASSWORD="testpassword"
## Create a code_verifier and code_challenge ##
CODE_CHALLENGE_METHOD="S256"
# code_verifier = random, 64-char string consisting of chars between letters,
# numbers, periods, underscores, tildes, or hyphens; the string
# is then base64-url encoded
code_verifier="$(cat /dev/urandom \
| tr -dc 'a-zA-Z0-9._~-' \
| fold -w 64 \
| head -n 1 \
| base64 \
| tr '+/' '-_' \
| tr -d '='
)"
# code_challenge = SHA-256 hash of the code_verifier; it is then base64-url
# encoded
code_challenge="$(printf "$code_verifier" \
| openssl dgst -sha256 -binary \
| base64 \
| tr '+/' '-_' \
| tr -d '='
)"
## Get CSRF token from /oauth2/authorize endpoint ##
curl_response="$(
curl -qv "https://${AUTH_DOMAIN}/oauth2/authorize?response_type=${RESPONSE_TYPE}&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&scope=${SCOPE}&code_challenge_method=${CODE_CHALLENGE_METHOD}&code_challenge=${code_challenge}" 2>&1
)"
curl_redirect="$(printf "%s" "$curl_response" \
| awk '/^< Location: / {
gsub(/\r/, ""); # Remove carriage returns
print ; # Print redirect URL
}')"
csrf_token="$(printf "%s" "$curl_response" \
| awk '/^< Set-Cookie:/ {
gsub(/^XSRF-TOKEN=|;$/, "", ); # Remove cookie name and semi-colon
print ; # Print cookie value
}')"
## Get auth code or tokens from /login endpoint ##
curl_response="$(
curl -qv "$curl_redirect" \
-H "Cookie: XSRF-TOKEN=${csrf_token}; Path=/; Secure; HttpOnly" \
-d "_csrf=${csrf_token}" \
-d "username=${USERNAME}" \
-d "password=${PASSWORD}" 2>&1
)"
curl_redirect="$(printf "%s" "$curl_response" \
| awk '/^< Location: / {
gsub(/\r/, ""); # Remove carriage returns
print ; # Print redirect URL
}'
)"
auth_code="$(printf "%s" "$curl_redirect" \
| awk '{
sub(/.*code=/, ""); # Remove everything before auth code
print; # Print auth code
}')"
## Get tokens from /oauth2/token endpoint ##
authorization="$(printf "${CLIENT_ID}:${CLIENT_SECRET}" \
| base64 \
| tr -d "\n" # Remove line feed
)"
GRANT_TYPE="authorization_code"
curl "https://${AUTH_DOMAIN}/oauth2/token" \
-H "Authorization: Basic ${authorization}" \
-d "grant_type=${GRANT_TYPE}" \
-d "client_id=${CLIENT_ID}" \
-d "code=${auth_code}" \
-d "redirect_uri=${REDIRECT_URI}" \
-d "code_verifier=${code_verifier}"
#===============================================================================
# CLIENT CREDENTIALS GRANT
#===============================================================================
## Set constants ##
CLIENT_ID="USER_POOL_CLIENT_ID"
CLIENT_SECRET="USER_POOL_CLIENT_SECRET"
GRANT_TYPE="client_credentials"
## Get access token from /oauth2/token endpoint ##
authorization="$(printf "${CLIENT_ID}:${CLIENT_SECRET}" \
| base64 \
| tr -d "\n" # Remove line feed
)"
curl "https://${AUTH_DOMAIN}/oauth2/token" \
-H "Authorization: Basic ${authorization}" \
-d "grant_type=${GRANT_TYPE}"
#===============================================================================
# LOGOUT
#===============================================================================
## Set constants ##
CLIENT_ID="USER_POOL_CLIENT_ID"
REDIRECT_URI="https://example.com/"
## Hit /logout endpoint ##
curl -v "https://${AUTH_DOMAIN}/logout?client_id=${CLIENT_ID}&logout_uri=${REDIRECT_URI}"