Server-side support for Next.js, Node.js, and other server environments with proper context isolation, OAuth handling, and server-specific utilities for Amplify operations.
import {
runWithAmplifyServerContext,
createKeyValueStorageFromCookieStorageAdapter,
createAWSCredentialsAndIdentityIdProvider,
createUserPoolsTokenProvider
} from "aws-amplify/adapter-core";Run Amplify operations within a server context with proper request isolation.
/**
* Execute operations within an Amplify server context
* @param context - Server context configuration
* @param operation - Function to execute within the context
* @returns Promise with the result of the operation
*/
function runWithAmplifyServerContext<T>(
context: AmplifyServer,
operation: (contextSpec: AmplifyServerContextSpec) => T | Promise<T>
): Promise<T>;
interface AmplifyServer {
config: ResourcesConfig;
cookies?: CookiesAdapter;
headers?: Record<string, string>;
request?: {
url: string;
method?: string;
headers?: Record<string, string>;
};
}
interface AmplifyServerContextSpec {
token: {
value: Symbol;
};
}
interface CookiesAdapter {
get(name: string): CookieValue | undefined;
getAll(): Record<string, CookieValue>;
set(name: string, value: string, options?: CookieOptions): void;
delete(name: string, options?: CookieOptions): void;
}
interface CookieValue {
name: string;
value: string;
}
interface CookieOptions {
domain?: string;
expires?: Date;
httpOnly?: boolean;
maxAge?: number;
path?: string;
priority?: 'low' | 'medium' | 'high';
sameSite?: boolean | 'lax' | 'strict' | 'none';
secure?: boolean;
}Server Context Usage:
import { runWithAmplifyServerContext } from "aws-amplify/adapter-core";
import { getCurrentUser } from "aws-amplify/auth/server";
import { cookies } from "next/headers";
// Next.js API route example
export async function GET(request: Request) {
return await runWithAmplifyServerContext({
config: {
Auth: {
Cognito: {
userPoolId: process.env.USER_POOL_ID!,
userPoolClientId: process.env.USER_POOL_CLIENT_ID!,
region: process.env.AWS_REGION!
}
}
},
cookies: {
get: (name) => {
const cookie = cookies().get(name);
return cookie ? { name: cookie.name, value: cookie.value } : undefined;
},
getAll: () => {
const allCookies: Record<string, CookieValue> = {};
cookies().getAll().forEach(cookie => {
allCookies[cookie.name] = { name: cookie.name, value: cookie.value };
});
return allCookies;
},
set: (name, value, options) => {
cookies().set(name, value, options);
},
delete: (name, options) => {
cookies().delete(name);
}
}
}, async (contextSpec) => {
try {
const user = await getCurrentUser();
return Response.json({ user });
} catch (error) {
return Response.json({ error: 'Not authenticated' }, { status: 401 });
}
});
}Create storage adapters for server environments using cookies and other storage mechanisms.
/**
* Create key-value storage from cookie storage adapter
* @param cookieStorageAdapter - Cookie storage implementation
* @returns KeyValueStorageInterface for server use
*/
function createKeyValueStorageFromCookieStorageAdapter(
cookieStorageAdapter: CookieStorageAdapter
): KeyValueStorageInterface;
interface CookieStorageAdapter {
get(name: string): string | undefined;
set(name: string, value: string, options?: CookieOptions): void;
delete(name: string): void;
}
interface KeyValueStorageInterface {
setItem(key: string, value: string): Promise<void> | void;
getItem(key: string): Promise<string | null> | string | null;
removeItem(key: string): Promise<void> | void;
clear(): Promise<void> | void;
}Storage Adapter Example:
import { createKeyValueStorageFromCookieStorageAdapter } from "aws-amplify/adapter-core";
import { cookies } from "next/headers";
// Create storage adapter using Next.js cookies
const cookieStorage = createKeyValueStorageFromCookieStorageAdapter({
get: (name) => cookies().get(name)?.value,
set: (name, value, options) => {
cookies().set(name, value, {
...options,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict'
});
},
delete: (name) => {
cookies().delete(name);
}
});
// Use in server context
await cookieStorage.setItem('user_preference', 'dark_mode');
const preference = await cookieStorage.getItem('user_preference');Create AWS credentials and token providers for server-side authentication.
/**
* Create AWS credentials and identity ID provider
* @param config - Provider configuration
* @returns Credentials provider for server use
*/
function createAWSCredentialsAndIdentityIdProvider(
config: CredentialsProviderConfig
): CredentialsAndIdentityIdProvider;
/**
* Create user pools token provider
* @param config - Token provider configuration
* @returns Token provider for server use
*/
function createUserPoolsTokenProvider(
config: TokenProviderConfig
): TokenProvider;
interface CredentialsProviderConfig {
authConfig: AuthConfig;
credentialsStorage: KeyValueStorageInterface;
identityStorage: KeyValueStorageInterface;
}
interface TokenProviderConfig {
authConfig: AuthConfig;
keyValueStorage: KeyValueStorageInterface;
}
interface CredentialsAndIdentityIdProvider {
getCredentialsAndIdentityId(): Promise<CredentialsAndIdentityId>;
clearCredentialsAndIdentityId(): Promise<void>;
}
interface TokenProvider {
getTokens(): Promise<AuthTokens>;
clearTokens(): Promise<void>;
}Server-side OAuth flow utilities for handling redirects and state management.
/**
* Generate OAuth state parameter
* @returns Random state string for OAuth flow
*/
function generateState(): string;
/**
* Get OAuth redirect URL
* @param config - OAuth configuration
* @returns Complete redirect URL for OAuth provider
*/
function getRedirectUrl(config: OAuthConfig): string;
/**
* Generate PKCE code verifier for OAuth
* @returns Code verifier string
*/
function generateCodeVerifier(): string;
/**
* Validate OAuth state parameter
* @param receivedState - State received from OAuth provider
* @param expectedState - Expected state value
* @returns Boolean indicating if state is valid
*/
function validateState(receivedState: string, expectedState: string): boolean;
interface OAuthConfig {
provider: string;
clientId: string;
redirectUri: string;
scopes: string[];
state?: string;
codeChallenge?: string;
codeChallengeMethod?: string;
}OAuth Server Example:
import {
generateState,
getRedirectUrl,
generateCodeVerifier,
validateState
} from "aws-amplify/adapter-core";
// Initiate OAuth flow
export async function initiateOAuth() {
const state = generateState();
const codeVerifier = generateCodeVerifier();
// Store state and code verifier securely
await storeOAuthData({ state, codeVerifier });
const redirectUrl = getRedirectUrl({
provider: 'Google',
clientId: process.env.GOOGLE_CLIENT_ID!,
redirectUri: `${process.env.NEXT_PUBLIC_BASE_URL}/auth/callback`,
scopes: ['openid', 'profile', 'email'],
state,
codeChallenge: await generateCodeChallenge(codeVerifier),
codeChallengeMethod: 'S256'
});
return Response.redirect(redirectUrl);
}
// Handle OAuth callback
export async function handleOAuthCallback(request: Request) {
const url = new URL(request.url);
const receivedState = url.searchParams.get('state');
const authCode = url.searchParams.get('code');
const storedData = await getStoredOAuthData();
if (!validateState(receivedState!, storedData.state)) {
return Response.json({ error: 'Invalid state' }, { status: 400 });
}
// Exchange code for tokens using stored code verifier
// ... token exchange logic
}Utilities for managing authentication storage keys and configuration.
/**
* Create storage keys for authentication data
* @param identifier - User or session identifier
* @returns Object with authentication storage keys
*/
function createKeysForAuthStorage(identifier: string): AuthStorageKeys;
/**
* Authentication storage key prefix
*/
const AUTH_KEY_PREFIX: string;
/**
* Default max age for authentication cookies (in seconds)
*/
const DEFAULT_AUTH_TOKEN_COOKIES_MAX_AGE: number;
interface AuthStorageKeys {
accessToken: string;
idToken: string;
refreshToken: string;
clockDrift: string;
signInDetails: string;
userData: string;
}Auth Storage Example:
import {
createKeysForAuthStorage,
AUTH_KEY_PREFIX,
DEFAULT_AUTH_TOKEN_COOKIES_MAX_AGE
} from "aws-amplify/adapter-core";
// Create storage keys for a user
const userId = 'user123';
const authKeys = createKeysForAuthStorage(userId);
console.log(authKeys);
// {
// accessToken: 'amplify_auth_user123_accessToken',
// idToken: 'amplify_auth_user123_idToken',
// refreshToken: 'amplify_auth_user123_refreshToken',
// clockDrift: 'amplify_auth_user123_clockDrift',
// signInDetails: 'amplify_auth_user123_signInDetails',
// userData: 'amplify_auth_user123_userData'
// }
// Set token with default expiration
cookies().set(authKeys.accessToken, tokenValue, {
maxAge: DEFAULT_AUTH_TOKEN_COOKIES_MAX_AGE,
secure: true,
httpOnly: true,
sameSite: 'strict'
});Server-specific versions of API, auth, and storage operations.
// Available from specific server imports
import { getCurrentUser, fetchAuthSession } from "aws-amplify/auth/server";
import { generateClient } from "aws-amplify/api/server";
// Or use the data alias: import { generateClient } from "aws-amplify/data/server";
import { getProperties, getUrl, list, remove, copy } from "aws-amplify/storage/server";
// Note: uploadData and downloadData are NOT available on server-side
// Use client-side operations for file upload/download functionalityServer API Usage:
import { runWithAmplifyServerContext } from "aws-amplify/adapter-core";
import { getCurrentUser } from "aws-amplify/auth/server";
import { generateClient } from "aws-amplify/api/server";
// Server-side API call
export async function serverAction() {
return await runWithAmplifyServerContext({
config: amplifyConfig,
cookies: cookiesAdapter
}, async (contextSpec) => {
// Get current user on server
const user = await getCurrentUser();
// Make GraphQL query on server
const client = generateClient();
const result = await client.graphql({
query: `query GetUserData($userId: ID!) {
getUser(id: $userId) {
id
name
email
}
}`,
variables: { userId: user.userId }
});
return result.data.getUser;
});
}Integration with Next.js middleware and other server frameworks.
// Next.js middleware example
import { NextRequest, NextResponse } from "next/server";
import { runWithAmplifyServerContext } from "aws-amplify/adapter-core";
import { fetchAuthSession } from "aws-amplify/auth/server";
export async function middleware(request: NextRequest) {
const response = NextResponse.next();
// Check authentication on protected routes
if (request.nextUrl.pathname.startsWith('/protected')) {
try {
await runWithAmplifyServerContext({
config: amplifyConfig,
cookies: {
get: (name) => request.cookies.get(name),
getAll: () => {
const cookies: Record<string, CookieValue> = {};
request.cookies.getAll().forEach(cookie => {
cookies[cookie.name] = cookie;
});
return cookies;
},
set: (name, value, options) => {
response.cookies.set(name, value, options);
},
delete: (name) => {
response.cookies.delete(name);
}
}
}, async () => {
const session = await fetchAuthSession();
if (!session.tokens) {
throw new Error('No valid session');
}
});
} catch (error) {
// Redirect to login if not authenticated
return NextResponse.redirect(new URL('/login', request.url));
}
}
return response;
}
export const config = {
matcher: ['/protected/:path*']
};// Server context types
interface AmplifyServer {
config: ResourcesConfig;
cookies?: CookiesAdapter;
headers?: Record<string, string>;
request?: ServerRequest;
}
interface ServerRequest {
url: string;
method?: string;
headers?: Record<string, string>;
body?: any;
}
// Legacy configuration support
interface LegacyConfig {
[key: string]: any;
}
// Amplify outputs format (deprecated)
interface AmplifyOutputs {
version: string;
auth?: any;
data?: any;
storage?: any;
custom?: any;
}
// Error types
class ServerError extends Error {
name: 'ServerError';
message: string;
statusCode?: number;
cause?: Error;
}
class ServerContextError extends ServerError {
name: 'ServerContextError';
}Server operations can encounter specific server-side errors:
import { runWithAmplifyServerContext, ServerError } from "aws-amplify/adapter-core";
try {
await runWithAmplifyServerContext(context, async () => {
// Server operations
});
} catch (error) {
if (error instanceof ServerError) {
switch (error.name) {
case 'ServerContextError':
console.log('Server context error:', error.message);
break;
case 'ConfigurationError':
console.log('Server configuration error:', error.message);
break;
default:
console.log('Server error:', error.message);
break;
}
} else {
console.log('Unexpected error:', error);
}
}runWithAmplifyServerContext for server operations