or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

authentication-lifecycle.mddevice-management.mdindex.mdmulti-factor-authentication.mdoauth-social-authentication.mdpassword-management.mdserver-side-apis.mdsession-management.mduser-management.mdwebauthn-credentials.md
tile.json

server-side-apis.mddocs/

Server-Side APIs

Dedicated server-side authentication APIs for SSR applications, backend services, and Next.js applications.

Server-Side Overview

The server-side APIs provide authentication functionality specifically designed for server environments. These APIs work with server-side sessions and cookies rather than client-side token storage.

Import Paths

// Main server export
import { getCurrentUser, fetchUserAttributes } from "@aws-amplify/auth/server";

// All server-side functionality
import * as AmplifyServer from "@aws-amplify/auth/server";

Get Current User (Server)

Retrieve the currently authenticated user in a server environment.

function getCurrentUser(): Promise<AuthUser>;

Usage Example

import { getCurrentUser } from "@aws-amplify/auth/server";

// In a Next.js API route or server component
export async function getServerSideProps(context) {
  try {
    const user = await getCurrentUser();
    
    return {
      props: {
        user: {
          username: user.username,
          userId: user.userId
        }
      }
    };
  } catch (error) {
    // User not authenticated
    return {
      redirect: {
        destination: '/login',
        permanent: false
      }
    };
  }
}

// In Express.js middleware
app.use(async (req, res, next) => {
  try {
    const user = await getCurrentUser();
    req.user = user;
    next();
  } catch (error) {
    res.status(401).json({ error: 'Unauthorized' });
  }
});

Fetch User Attributes (Server)

Get user attributes in a server environment.

function fetchUserAttributes(): Promise<FetchUserAttributesOutput>;

type FetchUserAttributesOutput = Record<UserAttributeKey, string>;

Usage Example

import { fetchUserAttributes } from "@aws-amplify/auth/server";

// In a Next.js API route
export default async function handler(req, res) {
  try {
    const attributes = await fetchUserAttributes();
    
    res.json({
      profile: {
        email: attributes.email,
        name: attributes.name,
        phoneNumber: attributes.phone_number
      }
    });
  } catch (error) {
    res.status(401).json({ error: 'User not authenticated' });
  }
}

// In server-side component
async function UserProfile() {
  try {
    const attributes = await fetchUserAttributes();
    
    return (
      <div>
        <h1>Welcome, {attributes.name}</h1>
        <p>Email: {attributes.email}</p>
      </div>
    );
  } catch (error) {
    return <div>Please sign in</div>;
  }
}

Next.js Integration

Complete integration with Next.js applications:

App Router (Next.js 13+)

// app/lib/auth.ts
import { getCurrentUser, fetchUserAttributes } from "@aws-amplify/auth/server";

export async function getServerUser() {
  try {
    const user = await getCurrentUser();
    const attributes = await fetchUserAttributes();
    
    return {
      user,
      attributes,
      isAuthenticated: true
    };
  } catch (error) {
    return {
      user: null,
      attributes: null,
      isAuthenticated: false
    };
  }
}

// app/dashboard/page.tsx
import { getServerUser } from '../lib/auth';
import { redirect } from 'next/navigation';

export default async function Dashboard() {
  const { user, attributes, isAuthenticated } = await getServerUser();
  
  if (!isAuthenticated) {
    redirect('/login');
  }
  
  return (
    <div>
      <h1>Dashboard</h1>
      <p>Welcome, {attributes?.name}</p>
      <p>User ID: {user?.userId}</p>
    </div>
  );
}

// app/api/profile/route.ts
import { fetchUserAttributes } from "@aws-amplify/auth/server";
import { NextResponse } from 'next/server';

export async function GET() {
  try {
    const attributes = await fetchUserAttributes();
    
    return NextResponse.json({
      success: true,
      profile: attributes
    });
  } catch (error) {
    return NextResponse.json(
      { success: false, error: 'Unauthorized' },
      { status: 401 }
    );
  }
}

Pages Router (Next.js 12 and earlier)

// lib/auth.js
import { getCurrentUser, fetchUserAttributes } from "@aws-amplify/auth/server";

export async function getServerSideUser(context) {
  try {
    const user = await getCurrentUser();
    const attributes = await fetchUserAttributes();
    
    return { user, attributes };
  } catch (error) {
    return { user: null, attributes: null };
  }
}

// pages/dashboard.js
import { getServerSideUser } from '../lib/auth';

export async function getServerSideProps(context) {
  const { user, attributes } = await getServerSideUser(context);
  
  if (!user) {
    return {
      redirect: {
        destination: '/login',
        permanent: false
      }
    };
  }
  
  return {
    props: {
      user: {
        username: user.username,
        userId: user.userId
      },
      profile: attributes
    }
  };
}

export default function Dashboard({ user, profile }) {
  return (
    <div>
      <h1>Welcome, {profile.name}</h1>
      <p>User ID: {user.userId}</p>
    </div>
  );
}

// pages/api/me.js
import { getCurrentUser, fetchUserAttributes } from "@aws-amplify/auth/server";

export default async function handler(req, res) {
  try {
    const user = await getCurrentUser();
    const attributes = await fetchUserAttributes();
    
    res.json({
      user: {
        username: user.username,
        userId: user.userId
      },
      attributes
    });
  } catch (error) {
    res.status(401).json({ error: 'Unauthorized' });
  }
}

Express.js Integration

Using server-side APIs with Express.js:

import express from 'express';
import { getCurrentUser, fetchUserAttributes } from "@aws-amplify/auth/server";

const app = express();

// Authentication middleware
async function requireAuth(req, res, next) {
  try {
    const user = await getCurrentUser();
    req.user = user;
    next();
  } catch (error) {
    res.status(401).json({ error: 'Authentication required' });
  }
}

// Protected route
app.get('/api/profile', requireAuth, async (req, res) => {
  try {
    const attributes = await fetchUserAttributes();
    
    res.json({
      user: req.user,
      profile: attributes
    });
  } catch (error) {
    res.status(500).json({ error: 'Failed to fetch profile' });
  }
});

// User info endpoint
app.get('/api/user', async (req, res) => {
  try {
    const user = await getCurrentUser();
    const attributes = await fetchUserAttributes();
    
    res.json({
      authenticated: true,
      user: {
        username: user.username,
        userId: user.userId,
        email: attributes.email,
        name: attributes.name
      }
    });
  } catch (error) {
    res.json({
      authenticated: false,
      user: null
    });
  }
});

app.listen(3000);

Server-Side Session Management

Managing authentication state on the server:

import { getCurrentUser, fetchUserAttributes } from "@aws-amplify/auth/server";

class ServerAuthManager {
  async getAuthenticatedUser() {
    try {
      const user = await getCurrentUser();
      const attributes = await fetchUserAttributes();
      
      return {
        isAuthenticated: true,
        user: {
          username: user.username,
          userId: user.userId,
          signInDetails: user.signInDetails
        },
        profile: attributes
      };
    } catch (error) {
      return {
        isAuthenticated: false,
        user: null,
        profile: null,
        error: error.message
      };
    }
  }
  
  async requireAuthentication() {
    const result = await this.getAuthenticatedUser();
    
    if (!result.isAuthenticated) {
      throw new Error('Authentication required');
    }
    
    return result;
  }
  
  async getUserId(): Promise<string | null> {
    try {
      const user = await getCurrentUser();
      return user.userId;
    } catch (error) {
      return null;
    }
  }
  
  async getUserAttribute(attributeKey: UserAttributeKey): Promise<string | null> {
    try {
      const attributes = await fetchUserAttributes();
      return attributes[attributeKey] || null;
    } catch (error) {
      return null;
    }
  }
}

// Usage
const authManager = new ServerAuthManager();

// In API handler
export async function apiHandler(req, res) {
  try {
    const { user, profile } = await authManager.requireAuthentication();
    
    // Process authenticated request
    res.json({ user, profile });
  } catch (error) {
    res.status(401).json({ error: 'Unauthorized' });
  }
}

Cookie and Session Handling

Server-side APIs work with HTTP cookies and server sessions:

// Cookie configuration for server-side auth
const cookieConfig = {
  httpOnly: true,
  secure: process.env.NODE_ENV === 'production',
  sameSite: 'strict',
  maxAge: 24 * 60 * 60 * 1000 // 24 hours
};

// Express middleware for cookie handling
app.use(cookieParser());

// Custom session validation
async function validateSession(req, res, next) {
  const sessionToken = req.cookies['amplify-session'];
  
  if (!sessionToken) {
    return res.status(401).json({ error: 'No session token' });
  }
  
  try {
    // Amplify handles session validation internally
    const user = await getCurrentUser();
    req.user = user;
    next();
  } catch (error) {
    // Clear invalid session cookie
    res.clearCookie('amplify-session');
    res.status(401).json({ error: 'Invalid session' });
  }
}

Error Handling

Handle server-side authentication errors:

import { getCurrentUser, AuthError } from "@aws-amplify/auth/server";

async function handleServerAuth(req, res) {
  try {
    const user = await getCurrentUser();
    return { success: true, user };
  } catch (error) {
    if (error instanceof AuthError) {
      switch (error.name) {
        case 'NotAuthorizedException':
          return { success: false, error: 'User not authenticated', statusCode: 401 };
        case 'UserNotConfirmedException':
          return { success: false, error: 'User not confirmed', statusCode: 403 };
        case 'TokenExpiredException':
          return { success: false, error: 'Session expired', statusCode: 401 };
        case 'NetworkError':
          return { success: false, error: 'Network error', statusCode: 503 };
        default:
          return { success: false, error: 'Authentication error', statusCode: 500 };
      }
    }
    
    return { success: false, error: 'Unknown error', statusCode: 500 };
  }
}

// Usage in API route
export default async function handler(req, res) {
  const { success, user, error, statusCode } = await handleServerAuth(req, res);
  
  if (!success) {
    return res.status(statusCode).json({ error });
  }
  
  // Continue with authenticated request
  res.json({ user });
}

Best Practices

Performance

  • Cache user data appropriately in server memory or Redis
  • Use connection pooling for database connections
  • Implement proper session timeout handling
  • Minimize API calls by batching operations

Security

  • Always validate sessions on the server side
  • Use secure cookies with appropriate flags
  • Implement proper CSRF protection
  • Validate user permissions for each request

Error Handling

  • Provide consistent error responses
  • Log authentication failures for monitoring
  • Handle token expiration gracefully
  • Implement proper retry logic for network errors

Monitoring

  • Track authentication success/failure rates
  • Monitor session duration and usage patterns
  • Set up alerts for authentication anomalies
  • Log security-relevant events