API: AWS authentication manual
This documentation demonstrates how to obtain JWT Bearer tokens from Amazon Cognito UsePools using Node.js.
We focus on Node.js because it provides dedicated client libraries that allow direct user authentication without requiring AWS CLI configuration, IAM roles, or AWS access keys.
Why Node.js for Cognito Authentication?
Unlike standard AWS SDKs in other languages (Python boto3, Java AWS SDK, .NET AWS SDK, etc.), which primarily expose administrative Cognito operations requiring AWS credentials, the Node.js ecosystem provides purpose-built client libraries specifically designed for end-user authentication:
-
amazon-cognito-identity-js (Legacy - Still functional)
-
AWS Amplify Auth (Modern - Recommended)
What Makes This Different?
|
Requirement |
Node.js Libraries (Amplify Auth / amazon-cognito-identity-js) |
Other AWS SDKs (Python/Java/.NET) |
|---|---|---|
|
AWS Access Keys |
Not needed |
Required |
|
AWS CLI Configuration |
Not needed |
Required |
|
IAM Roles |
Not needed |
Required |
|
What You Need |
User Pool ID + Client ID + User Credentials |
AWS credentials + User Pool info |
Core Concept: Node.js libraries allow you to authenticate users and retrieve JWT tokens using only:
-
User Pool ID (public identifier)
-
App Client ID (public identifier)
-
User credentials (uuid/password)
Authentication Goal
Primary Objective: Exchange user credentials for JWT tokens
What You'll Get:
-
ID Token - Contains user identity information and attributes. This is used to make API calls to your public APIs
-
Access Token - Used to authorize access to AWS Cognito User Pool APIs and AWS resources
-
Refresh Token - Used to obtain new ID/Access tokens when they expire
Option 1: AWS Amplify Auth (Recommended)
Why Amplify Auth?
-
Official AWS recommendation for user authentication
-
No AWS credentials required - works with User Pool config only
-
Active development and modern API design
-
Automatic token management and refresh
-
TypeScript support with full type definitions
System Requirements: Node.js 16.x or higher
Installation
npm install aws-amplify
Implementation
/**
* AWS Cognito Authentication using AWS Amplify Auth
* * Obtains JWT Bearer tokens (ID Token, Access Token, Refresh Token)
* without requiring AWS credentials. This is compatible with Cognito User Pools
* configured to use a UUID or similar identifier as the primary username.
*/
// The following is needed only in Node.js environments (do NOT include for browser or mobile apps)
const crypto = require('crypto');
global.crypto = crypto;
const { Amplify } = require('aws-amplify');
const { signIn, fetchAuthSession } = require('aws-amplify/auth');
// ============================================================================
// CONFIGURATION - Update with your Cognito User Pool details
// ============================================================================
const USER_POOL_ID = 'us-east-1_XXXXXXXXX'; // Your User Pool ID
const APP_CLIENT_ID = 'XXXXXXXXXXXXXXXXXXXXXX'; // Your App Client ID
const AWS_REGION = 'us-east-1'; // Your AWS region
const TEST_USERNAME = 'xxxx-xxxx-xxxx-xxxx-xxxx'; // User's UUID (used as username)
const TEST_PASSWORD = 'YourPassword123!'; // User's password
// Configure Amplify (no AWS credentials needed)
Amplify.configure({
Auth: {
Cognito: {
userPoolId: USER_POOL_ID,
userPoolClientId: APP_CLIENT_ID,
region: AWS_REGION
}
}
});
// ============================================================================
// AUTHENTICATE AND GET TOKENS
// ============================================================================
/**
* Authenticate user and retrieve JWT tokens
*/
async function authenticateUser(username, password) {
try {
// Step 1: Sign in with credentials
await signIn({
username: username,
password: password
});
// Step 2: Retrieve session tokens
const session = await fetchAuthSession();
console.log('Authentication Successful\n');
console.log('ID Token:', session.tokens?.idToken?.toString());
console.log('\nAccess Token:', session.tokens?.accessToken?.toString());
console.log('\nRefresh Token:', session.tokens?.refreshToken?.toString());
return {
idToken: session.tokens?.idToken?.toString(),
accessToken: session.tokens?.accessToken?.toString(),
refreshToken: session.tokens?.refreshToken?.toString()
};
} catch (error) {
console.error('Authentication failed:', error.message);
throw error;
}
}
/**
* Refresh expired tokens using refresh token
*/
async function refreshTokens() {
try {
// Force token refresh
const session = await fetchAuthSession({ forceRefresh: true });
console.log('Tokens Refreshed Successfully\n');
console.log('New ID Token:', session.tokens?.idToken?.toString());
console.log('\nNew Access Token:', session.tokens?.accessToken?.toString());
return {
idToken: session.tokens?.idToken?.toString(),
accessToken: session.tokens?.accessToken?.toString(),
refreshToken: session.tokens?.refreshToken?.toString()
};
} catch (error) {
console.error('Token refresh failed:', error.message);
throw error;
}
}
// ============================================================================
// MAIN EXECUTION
// ============================================================================
async function main() {
try {
console.log('Authenticating user...\n');
// Get initial tokens
const tokens = await authenticateUser(TEST_USERNAME, TEST_PASSWORD);
console.log('\nSuccessfully obtained JWT tokens');
// Updated message to emphasize ID Token for API access
console.log('You can now use the ID Token as a Bearer token to access your API resources.\n');
// Optional: Demonstrate token refresh
// Uncomment the following lines to test token refresh:
/*
console.log('\nRefreshing tokens...\n');
const refreshedTokens = await refreshTokens();
console.log('\nSuccessfully refreshed tokens');
*/
} catch (error) {
console.error('\nError:', error.message);
process.exit(1);
}
}
main();
Usage Instructions
Step 1: Install dependencies
npm install aws-amplify
Step 2: Update configuration
-
Set your
USER_POOL_ID -
Set your
APP_CLIENT_ID -
Set your
AWS_REGION -
Set your
TEST_USERNAMEandTEST_PASSWORD
Step 3: Run the script
node amplify-auth.js
Step 4: Expected Output
Authentication Successful
ID Token: eyJraWQiOiJ....(long JWT string)
Access Token: eyJraWQiOiJ....(long JWT string)
Refresh Token: eyJjdHkiOiJ....(long JWT string)
Option 2: amazon-cognito-identity-js (Legacy)
Why This Option?
-
Legacy library - AWS recommends migrating to Amplify
-
Still functional and widely used in existing projects
-
No AWS credentials required - same advantage as Amplify
-
Lightweight with minimal dependencies
System Requirements: Node.js 14.x or higher
Installation
npm install amazon-cognito-identity-js
Implementation
/**
* AWS Cognito Authentication using amazon-cognito-identity-js
* * Obtains JWT Bearer tokens (ID Token, Access Token, Refresh Token)
* without requiring AWS credentials. This version is compatible with Cognito User Pools
* configured to use a UUID or similar identifier as the primary username.
*/
const {
CognitoUserPool,
CognitoUser,
AuthenticationDetails,
CognitoRefreshToken
} = require('amazon-cognito-identity-js');
// ============================================================================
// CONFIGURATION - Update with your Cognito User Pool details
// ============================================================================
const USER_POOL_ID = 'us-east-1_XXXXXXXXX'; // Your User Pool ID
const APP_CLIENT_ID = 'XXXXXXXXXXXXXXXXXXXXXX'; // Your App Client ID
const TEST_USERNAME = 'xxxx-xxxx-xxxx-xxxx-xxxx'; // User's UUID (used as username)
const TEST_PASSWORD = 'YourPassword123!'; // User's password
// ============================================================================
// AUTHENTICATE AND GET TOKENS
// ============================================================================
/**
* Authenticate user and retrieve JWT tokens
*/
async function authenticateUser(username, password) {
return new Promise((resolve, reject) => {
// Create User Pool instance
const userPool = new CognitoUserPool({
UserPoolId: USER_POOL_ID,
ClientId: APP_CLIENT_ID
});
// Create Cognito User instance
const cognitoUser = new CognitoUser({
Username: username,
Pool: userPool
});
// Create authentication details
const authDetails = new AuthenticationDetails({
Username: username,
Password: password
});
// Authenticate
cognitoUser.authenticateUser(authDetails, {
onSuccess: (result) => {
console.log('Authentication Successful\n');
console.log('ID Token:', result.getIdToken().getJwtToken());
console.log('\nAccess Token:', result.getAccessToken().getJwtToken());
console.log('\nRefresh Token:', result.getRefreshToken().getToken());
resolve({
idToken: result.getIdToken().getJwtToken(),
accessToken: result.getAccessToken().getJwtToken(),
refreshToken: result.getRefreshToken().getToken()
});
},
onFailure: (error) => {
console.error('Authentication failed:', error.message);
reject(error);
}
});
});
}
/**
* Refresh expired tokens using refresh token
*/
async function refreshTokens(refreshToken, username) {
return new Promise((resolve, reject) => {
// Create User Pool instance
const userPool = new CognitoUserPool({
UserPoolId: USER_POOL_ID,
ClientId: APP_CLIENT_ID
});
// Create Cognito User instance
const cognitoUser = new CognitoUser({
Username: username,
Pool: userPool
});
// Create refresh token object
const refreshTokenObj = new CognitoRefreshToken({
RefreshToken: refreshToken
});
// Refresh session
cognitoUser.refreshSession(refreshTokenObj, (error, session) => {
if (error) {
console.error('Token refresh failed:', error.message);
reject(error);
} else {
console.log('Tokens Refreshed Successfully\n');
console.log('New ID Token:', session.getIdToken().getJwtToken());
console.log('\nNew Access Token:', session.getAccessToken().getJwtToken());
// This SDK returns the old refresh token if a new one is not issued
const newRefreshToken = session.getRefreshToken() ? session.getRefreshToken().getToken() : refreshToken;
resolve({
idToken: session.getIdToken().getJwtToken(),
accessToken: session.getAccessToken().getJwtToken(),
refreshToken: newRefreshToken
});
}
});
});
}
// ============================================================================
// MAIN EXECUTION
// ============================================================================
async function main() {
try {
console.log('Authenticating user...\n');
// Get initial tokens
const tokens = await authenticateUser(TEST_USERNAME, TEST_PASSWORD);
console.log('\nSuccessfully obtained JWT tokens');
// Updated message to emphasize ID Token for API access
console.log('You can now use the ID Token as a Bearer token to access your API resources.\n');
// Optional: Demonstrate token refresh
// Uncomment the following lines to test token refresh:
/*
console.log('\nRefreshing tokens...\n');
const refreshedTokens = await refreshTokens(tokens.refreshToken, TEST_USERNAME);
console.log('\nSuccessfully refreshed tokens');
*/
} catch (error) {
console.error('\nError:', error.message);
process.exit(1);
}
}
main();Usage Instructions
Step 1: Install dependencies
npm install amazon-cognito-identity-js
Step 2: Update configuration
-
Set your
USER_POOL_ID -
Set your
APP_CLIENT_ID -
Set your
TEST_USERNAMEandTEST_PASSWORD
Step 3: Run the script
node cognito-identity-auth.js
Step 4: Expected Output
Authentication Successful
ID Token: eyJraWQiOiJ....(long JWT string)
Access Token: eyJraWQiOiJ....(long JWT string)
Refresh Token: eyJjdHkiOiJ....(long JWT string)
Token Refresh Flow
When to Refresh Tokens
-
In our setup, ID and Access tokens expire after 10 minutes, but the refresh token remains valid for 1 hour
-
Before making API calls, check token expiration
-
Use refresh token to get new tokens without re-authenticating
Refresh Token Example
AWS Amplify:
const session = await fetchAuthSession({ forceRefresh: true });
const newIdToken = session.tokens?.idToken?.toString();
amazon-cognito-identity-js:
const refreshedTokens = await refreshTokens(
existingRefreshToken,
username
);
const newIdToken = refreshedTokens.idToken;
Making Authorized API Calls
Once the ID Token is successfully obtained, it must be included in the HTTP request headers along with the mandatory custom Client header.
The ID Token expires after approximately 10 minutes and must be refreshed using the Refresh Token before making subsequent calls.
Required Headers
|
Header Key |
Value Format |
Purpose |
|---|---|---|
|
|
|
OAuth 2.0 authorization using the ID Token. |
|
|
|
Custom identifier for your client application. |
Available Endpoints
|
Method |
Endpoint |
Description |
|---|---|---|
|
|
|
Retrieve a list of public issues. |
|
|
|
Retrieve a specific public issue by ID. |
CURL Request Example
1.Get All Issues (List)
curl -X GET 'https://client-api.speakup.cloud/v1/public/issues' \
-H 'Authorization: Bearer <YOUR_ID_TOKEN_HERE>' \
-H 'Client: <CLIENT_SYSTEM_NAME>'
2. Get a Specific Issue (By ID)
curl -X GET 'https://client-api.speakup.cloud/v1/public/issues/<ISSUE_ID_HERE>' \
-H 'Authorization: Bearer <YOUR_ID_TOKEN_HERE>' \
-H 'Client: <CLIENT_SYSTEM_NAME>'
Note: You must replace all bracketed placeholders in the curl commands:
-
<ISSUE_ID_HERE>: The actual unique identifier of the specific issue you want to retrieve. -
<YOUR_ID_TOKEN_HERE>: Your valid and current Bearer token (ID token or access token) used for authorization. -
<CLIENT_SYSTEM_NAME>: The client system name.How to Find the
<CLIENT_SYSTEM_NAME>:This name is typically derived from the subdomain of your system's URL.
Example:
If your system's login URL is:
https://showroom.client.speakup.cloud/loginThen your
<CLIENT_SYSTEM_NAME>isshowroom.
Comparison Summary
|
Feature |
AWS Amplify Auth |
amazon-cognito-identity-js |
|---|---|---|
|
AWS Recommendation |
Yes |
Deprecated |
|
Requires AWS Credentials |
No |
No |
|
Active Development |
Yes |
Maintenance only |
|
TypeScript Support |
Full |
Limited |
|
Setup Complexity |
Simple |
Simple |
|
Use for New Projects |
Recommended |
Not recommended |
|
Use for Legacy Projects |
Migrate when possible |
Continue using |
Key Takeaways
-
No AWS Credentials Required: Both libraries work without AWS CLI, access keys, or IAM roles
-
Node.js Advantage: Dedicated client libraries designed specifically for user authentication
-
Choose Amplify: For new projects, AWS Amplify Auth is the recommended approach
-
Both Work: Legacy library still functional but plan migration to Amplify
Error Handling
Common Errors
NotAuthorizedException
-
Cause: Invalid username or password
-
Solution: Verify user credentials
UserNotFoundException
-
Cause: User doesn't exist in the User Pool
-
Solution: Check username and ensure user is created
UserNotConfirmedException
-
Cause: User account not confirmed
-
Solution: Confirm user account via email/phone verification
TooManyRequestsException
-
Cause: Rate limit exceeded
-
Solution: Implement retry logic with exponential backoff
NetworkError
-
Cause: Network connectivity issue
-
Solution: Check internet connection and AWS service availability
Error Handling Example
async function authenticateWithErrorHandling(username, password) {
try {
const tokens = await authenticateUser(username, password);
return tokens;
} catch (error) {
switch (error.code || error.name) {
case 'NotAuthorizedException':
console.error('Invalid credentials');
break;
case 'UserNotFoundException':
console.error('User not found');
break;
case 'UserNotConfirmedException':
console.error('User account not confirmed');
break;
default:
console.error('Authentication failed:', error.message);
}
throw error;
}
}
Summary
This documentation provides two working approaches for obtaining JWT Bearer tokens from Amazon Cognito User Pools using Node.js, both of which do not require AWS credentials:
-
AWS Amplify Auth (Recommended for new projects)
-
amazon-cognito-identity-js (Legacy, but still functional)
Both libraries leverage Node.js-specific client implementations that allow direct user authentication without the need for AWS CLI configuration, IAM roles, or AWS access keys. This makes Node.js the ideal choice for client-side authentication scenarios where AWS credential management is not desired or feasible.