Authentication session and token management including automatic refresh, secure storage, and AWS credentials integration.
Get the current authentication session including tokens and AWS credentials.
function fetchAuthSession(options?: FetchAuthSessionOptions): Promise<AuthSession>;
interface FetchAuthSessionOptions {
forceRefresh?: boolean;
}
interface AuthSession {
tokens?: AuthTokens;
credentials?: AWSCredentials;
identityId?: string;
userSub?: string;
}
interface AuthTokens {
accessToken: JWT;
idToken?: JWT;
refreshToken?: string;
}
interface AWSCredentials {
accessKeyId: string;
secretAccessKey: string;
sessionToken?: string;
expiration?: Date;
}import { fetchAuthSession } from "@aws-amplify/auth";
// Get current session
const session = await fetchAuthSession();
if (session.tokens) {
console.log("User is signed in");
console.log("Access token expires:", session.tokens.accessToken.payload.exp);
console.log("User ID:", session.userSub);
// Access AWS credentials for API calls
if (session.credentials) {
console.log("AWS credentials available");
console.log("Identity ID:", session.identityId);
}
} else {
console.log("User not signed in");
}
// Force token refresh
const refreshedSession = await fetchAuthSession({
forceRefresh: true
});Decode and inspect JWT tokens without verification.
function decodeJWT(token: string): JWT;
interface JWT {
header: JWTHeader;
payload: JWTPayload;
signature: string;
toString(): string;
}
interface JWTHeader {
alg: string;
typ: string;
kid?: string;
}
interface JWTPayload {
sub: string;
aud: string;
iss: string;
exp: number;
iat: number;
token_use: 'access' | 'id';
scope?: string;
[key: string]: any;
}import { fetchAuthSession, decodeJWT } from "@aws-amplify/auth";
const session = await fetchAuthSession();
if (session.tokens?.accessToken) {
const decoded = decodeJWT(session.tokens.accessToken.toString());
console.log("Token issuer:", decoded.payload.iss);
console.log("Token audience:", decoded.payload.aud);
console.log("Token expires:", new Date(decoded.payload.exp * 1000));
console.log("Token scopes:", decoded.payload.scope);
// Check if token is expired
const isExpired = decoded.payload.exp * 1000 < Date.now();
console.log("Token expired:", isExpired);
}Managing authentication state across your application:
import { fetchAuthSession, getCurrentUser } from "@aws-amplify/auth";
class SessionManager {
private session: AuthSession | null = null;
private sessionListeners: ((session: AuthSession | null) => void)[] = [];
// Initialize session on app start
async initialize() {
try {
await this.refreshSession();
} catch (error) {
console.log("No active session");
this.session = null;
this.notifyListeners();
}
}
// Get current session
async getSession(): Promise<AuthSession | null> {
if (!this.session) {
try {
await this.refreshSession();
} catch (error) {
return null;
}
}
// Check if tokens are about to expire (within 5 minutes)
if (this.session?.tokens?.accessToken) {
const expiryTime = this.session.tokens.accessToken.payload.exp * 1000;
const fiveMinutesFromNow = Date.now() + (5 * 60 * 1000);
if (expiryTime < fiveMinutesFromNow) {
try {
await this.refreshSession(true);
} catch (error) {
console.log("Token refresh failed:", error);
this.session = null;
}
}
}
return this.session;
}
// Refresh session
async refreshSession(forceRefresh = false) {
this.session = await fetchAuthSession({ forceRefresh });
this.notifyListeners();
return this.session;
}
// Check if user is authenticated
async isAuthenticated(): Promise<boolean> {
const session = await this.getSession();
return !!(session?.tokens?.accessToken);
}
// Get AWS credentials
async getCredentials(): Promise<AWSCredentials | null> {
const session = await this.getSession();
return session?.credentials || null;
}
// Listen to session changes
onSessionChange(listener: (session: AuthSession | null) => void) {
this.sessionListeners.push(listener);
// Return unsubscribe function
return () => {
const index = this.sessionListeners.indexOf(listener);
if (index > -1) {
this.sessionListeners.splice(index, 1);
}
};
}
private notifyListeners() {
this.sessionListeners.forEach(listener => {
listener(this.session);
});
}
// Clear session on sign out
clearSession() {
this.session = null;
this.notifyListeners();
}
}
// Global session manager instance
export const sessionManager = new SessionManager();
// Usage in React component
import { useEffect, useState } from 'react';
function useAuthSession() {
const [session, setSession] = useState<AuthSession | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Initialize session
sessionManager.getSession().then(session => {
setSession(session);
setLoading(false);
});
// Listen to session changes
const unsubscribe = sessionManager.onSessionChange(session => {
setSession(session);
setLoading(false);
});
return unsubscribe;
}, []);
return { session, loading, isAuthenticated: !!session?.tokens };
}Understanding different token types and their purposes:
import { fetchAuthSession, decodeJWT } from "@aws-amplify/auth";
class TokenManager {
async analyzeTokens() {
const session = await fetchAuthSession();
if (!session.tokens) {
console.log("No tokens available");
return;
}
// Access Token - for API authorization
if (session.tokens.accessToken) {
const accessToken = decodeJWT(session.tokens.accessToken.toString());
console.log("=== ACCESS TOKEN ===");
console.log("Purpose: API authorization");
console.log("Expires:", new Date(accessToken.payload.exp * 1000));
console.log("Scopes:", accessToken.payload.scope);
console.log("Client ID:", accessToken.payload.client_id);
}
// ID Token - user identity information
if (session.tokens.idToken) {
const idToken = decodeJWT(session.tokens.idToken.toString());
console.log("=== ID TOKEN ===");
console.log("Purpose: User identity");
console.log("Email:", idToken.payload.email);
console.log("Email verified:", idToken.payload.email_verified);
console.log("Name:", idToken.payload.name);
console.log("Groups:", idToken.payload['cognito:groups']);
}
// Refresh Token - for obtaining new tokens
if (session.tokens.refreshToken) {
console.log("=== REFRESH TOKEN ===");
console.log("Purpose: Token refresh");
console.log("Available: Yes");
}
}
// Extract user info from ID token
getUserInfo(): any {
const session = this.getCurrentSession();
if (session?.tokens?.idToken) {
const idToken = decodeJWT(session.tokens.idToken.toString());
return {
sub: idToken.payload.sub,
email: idToken.payload.email,
emailVerified: idToken.payload.email_verified,
name: idToken.payload.name,
givenName: idToken.payload.given_name,
familyName: idToken.payload.family_name,
groups: idToken.payload['cognito:groups'] || [],
customAttributes: this.extractCustomAttributes(idToken.payload)
};
}
return null;
}
private extractCustomAttributes(payload: any): Record<string, any> {
const customAttrs: Record<string, any> = {};
Object.keys(payload).forEach(key => {
if (key.startsWith('custom:')) {
customAttrs[key.replace('custom:', '')] = payload[key];
}
});
return customAttrs;
}
}Using session credentials with AWS SDK:
import { fetchAuthSession } from "@aws-amplify/auth";
import { S3Client, ListObjectsV2Command } from "@aws-sdk/client-s3";
class AWSIntegration {
async createS3Client(): Promise<S3Client> {
const session = await fetchAuthSession();
if (!session.credentials) {
throw new Error("No AWS credentials available");
}
return new S3Client({
region: 'us-east-1',
credentials: {
accessKeyId: session.credentials.accessKeyId,
secretAccessKey: session.credentials.secretAccessKey,
sessionToken: session.credentials.sessionToken
}
});
}
async listS3Objects(bucket: string) {
const s3Client = await this.createS3Client();
const command = new ListObjectsV2Command({
Bucket: bucket,
MaxKeys: 10
});
try {
const response = await s3Client.send(command);
return response.Contents || [];
} catch (error) {
console.log("S3 operation failed:", error);
throw error;
}
}
// Generic AWS API call helper
async withAWSCredentials<T>(
operation: (credentials: AWSCredentials) => Promise<T>
): Promise<T> {
const session = await fetchAuthSession();
if (!session.credentials) {
throw new Error("No AWS credentials available");
}
return operation(session.credentials);
}
}
// Usage
const awsIntegration = new AWSIntegration();
// List S3 objects
const objects = await awsIntegration.listS3Objects('my-bucket');
// Use with any AWS SDK client
await awsIntegration.withAWSCredentials(async (credentials) => {
const dynamoClient = new DynamoDBClient({
region: 'us-east-1',
credentials: {
accessKeyId: credentials.accessKeyId,
secretAccessKey: credentials.secretAccessKey,
sessionToken: credentials.sessionToken
}
});
// Perform DynamoDB operations
});Handle session-related errors gracefully:
import { fetchAuthSession, AuthError } from "@aws-amplify/auth";
try {
const session = await fetchAuthSession();
} catch (error) {
if (error instanceof AuthError) {
switch (error.name) {
case 'NotAuthorizedException':
console.log('User not signed in');
// Redirect to sign-in
break;
case 'UserNotConfirmedException':
console.log('User email not confirmed');
// Redirect to confirmation
break;
case 'PasswordResetRequiredException':
console.log('Password reset required');
// Redirect to password reset
break;
case 'UserNotFoundException':
console.log('User not found');
// Clear stored credentials
break;
case 'NetworkError':
console.log('Network error occurred');
// Show offline message
break;
default:
console.log('Session error:', error.message);
}
}
}
// Handle token refresh failures
try {
await fetchAuthSession({ forceRefresh: true });
} catch (error) {
if (error instanceof AuthError && error.name === 'NotAuthorizedException') {
// Refresh token expired, user needs to sign in again
console.log('Session expired, please sign in again');
// Clear local session and redirect to sign-in
}
}