npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nicelogin-nextjs

v0.1.1

Published

NiceLogin SDK for Next.js - Complete authentication solution with Server Components, Server Actions, and Edge Middleware

Readme

nicelogin-nextjs

SDK completo de autenticacao para Next.js 13+ (App Router). Combina verificacao JWT RS256 local com JWKS, Server Components, Server Actions e Edge Middleware.

Instalacao

npm install nicelogin-nextjs

Estrutura de Arquivos Necessaria

Apos instalar, crie os seguintes arquivos na sua aplicacao Next.js:

app/
├── layout.tsx                      # Adicionar NiceLoginProvider
├── api/
│   └── auth/
│       ├── session/route.ts        # GET - retorna sessao atual
│       ├── login/route.ts          # POST - login
│       ├── logout/route.ts         # POST - logout
│       ├── register/route.ts       # POST - registro
│       └── oauth/
│           └── [provider]/route.ts # GET - redirect OAuth
├── login/page.tsx                  # Pagina de login
├── register/page.tsx               # Pagina de registro
└── dashboard/page.tsx              # Pagina protegida (exemplo)
middleware.ts                       # Protecao de rotas
.env.local                          # Variaveis de ambiente

Configuracao Passo a Passo

Passo 1: Variaveis de Ambiente

Crie .env.local na raiz do projeto:

NEXT_PUBLIC_NICELOGIN_API_KEY=nicelogin_sua_api_key_aqui

Passo 2: Configuracao do Servidor

Crie lib/auth.ts para inicializar o SDK no servidor:

// lib/auth.ts
import { initializeConfig } from 'nicelogin-nextjs';

// Inicializa configuracao (chamado automaticamente nas API routes)
export function initAuth() {
  initializeConfig({
    apiKey: process.env.NEXT_PUBLIC_NICELOGIN_API_KEY!,
  });
}

Passo 3: Provider no Layout

// app/layout.tsx
import { NiceLoginProvider } from 'nicelogin-nextjs/client';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="pt-BR">
      <body>
        <NiceLoginProvider>
          {children}
        </NiceLoginProvider>
      </body>
    </html>
  );
}

Passo 4: Middleware de Protecao

// middleware.ts (na raiz do projeto, mesmo nivel que app/)
import { withAuth } from 'nicelogin-nextjs/middleware';

export default withAuth({
  publicRoutes: ['/', '/login', '/register', '/api/auth/(.*)'],
  loginUrl: '/login',
});

export const config = {
  matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};

Passo 5: API Routes de Autenticacao

Crie todas as rotas de API:

// app/api/auth/session/route.ts
import { NextResponse } from 'next/server';
import { getSession, initializeConfig } from 'nicelogin-nextjs';

export async function GET() {
  initializeConfig({ apiKey: process.env.NEXT_PUBLIC_NICELOGIN_API_KEY! });
  const session = await getSession();
  return NextResponse.json({ session });
}
// app/api/auth/login/route.ts
import { NextResponse } from 'next/server';
import { signIn, initializeConfig } from 'nicelogin-nextjs';

export async function POST(request: Request) {
  initializeConfig({ apiKey: process.env.NEXT_PUBLIC_NICELOGIN_API_KEY! });
  const formData = await request.formData();
  const result = await signIn(formData);
  return NextResponse.json(result);
}
// app/api/auth/logout/route.ts
import { NextResponse } from 'next/server';
import { signOut, initializeConfig } from 'nicelogin-nextjs';

export async function POST() {
  initializeConfig({ apiKey: process.env.NEXT_PUBLIC_NICELOGIN_API_KEY! });
  const result = await signOut();
  return NextResponse.json(result);
}
// app/api/auth/register/route.ts
import { NextResponse } from 'next/server';
import { signUp, initializeConfig } from 'nicelogin-nextjs';

export async function POST(request: Request) {
  initializeConfig({ apiKey: process.env.NEXT_PUBLIC_NICELOGIN_API_KEY! });
  const formData = await request.formData();
  const result = await signUp(formData);
  return NextResponse.json(result);
}
// app/api/auth/oauth/[provider]/route.ts
import { NextResponse } from 'next/server';
import { getOAuthUrl, initializeConfig } from 'nicelogin-nextjs';

export async function GET(
  request: Request,
  { params }: { params: { provider: string } }
) {
  initializeConfig({ apiKey: process.env.NEXT_PUBLIC_NICELOGIN_API_KEY! });

  const provider = params.provider as 'google' | 'github' | 'discord' | 'apple';
  const redirectUri = `${process.env.NEXT_PUBLIC_APP_URL}/api/auth/oauth/${provider}/callback`;

  const { authorization_url } = await getOAuthUrl(
    provider,
    process.env.NEXT_PUBLIC_NICELOGIN_API_KEY!,
    redirectUri
  );

  return NextResponse.redirect(authorization_url);
}

Uso

Client Components (Hooks)

'use client';

import { useNiceLogin } from 'nicelogin-nextjs/client';

export function UserProfile() {
  const { user, isAuthenticated, isLoading, logout } = useNiceLogin();

  if (isLoading) return <div>Carregando...</div>;
  if (!isAuthenticated) return <div>Nao autenticado</div>;

  return (
    <div>
      <p>Email: {user?.email}</p>
      <button onClick={() => logout()}>Sair</button>
    </div>
  );
}

Server Components

// app/dashboard/page.tsx
import { redirect } from 'next/navigation';
import { getSession, initializeConfig } from 'nicelogin-nextjs';

export default async function DashboardPage() {
  initializeConfig({ apiKey: process.env.NEXT_PUBLIC_NICELOGIN_API_KEY! });

  const session = await getSession();
  if (!session) {
    redirect('/login');
  }

  return (
    <div>
      <h1>Bem-vindo, {session.user.email}!</h1>
      <p>ID: {session.user.id}</p>
    </div>
  );
}

Componentes Pre-Prontos

'use client';

import { LoginForm, RegisterForm, SignOutButton, AuthGuard } from 'nicelogin-nextjs/client';

// Formulario de login
<LoginForm 
  onSuccess={() => window.location.href = '/dashboard'} 
  onError={(err) => console.error(err)}
/>

// Formulario de registro
<RegisterForm 
  redirectTo="/dashboard"
  requirePasswordConfirmation={true}
/>

// Botao de logout
<SignOutButton redirectTo="/login">
  Sair da conta
</SignOutButton>

// Protecao de conteudo
<AuthGuard 
  fallback={<p>Faca login para ver este conteudo</p>}
  loadingComponent={<p>Carregando...</p>}
>
  <SecretContent />
</AuthGuard>

OAuth (Login Social)

'use client';

import { useNiceLogin } from 'nicelogin-nextjs/client';

export function SocialLogin() {
  const { loginWithOAuth } = useNiceLogin();

  return (
    <div>
      <button onClick={() => loginWithOAuth('google')}>
        Entrar com Google
      </button>
      <button onClick={() => loginWithOAuth('github')}>
        Entrar com GitHub
      </button>
      <button onClick={() => loginWithOAuth('discord')}>
        Entrar com Discord
      </button>
      <button onClick={() => loginWithOAuth('apple')}>
        Entrar com Apple
      </button>
    </div>
  );
}

API Reference

Hooks

| Hook | Descricao | |------|-----------| | useNiceLogin() | Hook principal com user, login, logout, register | | useSession() | Hook para estado da sessao com polling |

Server Functions

| Funcao | Descricao | |--------|-----------| | getSession() | Obtem sessao atual (ou null) | | getAuthenticatedUser() | Obtem usuario (throws se nao autenticado) | | requireSession(redirectTo) | Obtem sessao ou redireciona | | verifyToken(token) | Verifica e decodifica JWT | | isTokenValid(token) | Verifica se token e valido (boolean) |

Server Actions

| Action | Descricao | |--------|-----------| | signIn(formData) | Login com email/password | | signOut() | Logout (limpa cookies) | | signUp(formData) | Registro + auto-login | | requestPasswordReset(formData) | Solicita reset de senha |

Middleware

| Funcao | Descricao | |--------|-----------| | withAuth(options) | HOF para criar middleware de auth | | createAuthMiddleware(options) | Cria middleware diretamente |

Componentes

| Componente | Descricao | |------------|-----------| | NiceLoginProvider | Provider para envolver a app | | LoginForm | Formulario de login | | RegisterForm | Formulario de registro | | SignOutButton | Botao de logout | | AuthGuard | Componente de protecao |

Seguranca

  • Tokens armazenados em cookies HttpOnly
  • Verificacao RS256 local com JWKS (sem chamadas extras a API)
  • Cache de JWKS por 24h
  • Protecao CSRF integrada
  • Compativel com Edge Runtime

Diferencas vs nicelogin-react

| Aspecto | nicelogin-react | nicelogin-nextjs | |---------|-----------------|------------------| | Storage | localStorage | Cookies HttpOnly | | Verificacao | Apenas decode | RS256 completo | | Server-side | Nao | Server Components + Actions | | Middleware | Nao | Edge runtime | | OAuth | Nao | 4 provedores | | SSR | Nao | Completo |

Exemplos Completos de Paginas

Pagina de Login

// app/login/page.tsx
'use client';

import { useState } from 'react';
import { useNiceLogin } from 'nicelogin-nextjs/client';
import { useRouter } from 'next/navigation';
import Link from 'next/link';

export default function LoginPage() {
  const router = useRouter();
  const { login, loginWithOAuth, isLoading } = useNiceLogin();
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState('');

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setError('');

    try {
      await login(email, password);
      router.push('/dashboard');
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Erro ao fazer login');
    }
  };

  return (
    <div style={{ maxWidth: 400, margin: '100px auto', padding: 20 }}>
      <h1>Login</h1>

      {error && <p style={{ color: 'red' }}>{error}</p>}

      <form onSubmit={handleSubmit}>
        <div style={{ marginBottom: 15 }}>
          <label>Email</label>
          <input
            type="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            required
            style={{ width: '100%', padding: 8 }}
          />
        </div>

        <div style={{ marginBottom: 15 }}>
          <label>Senha</label>
          <input
            type="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
            required
            style={{ width: '100%', padding: 8 }}
          />
        </div>

        <button type="submit" disabled={isLoading} style={{ width: '100%', padding: 10 }}>
          {isLoading ? 'Entrando...' : 'Entrar'}
        </button>
      </form>

      <hr style={{ margin: '20px 0' }} />

      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        <button onClick={() => loginWithOAuth('google')}>Entrar com Google</button>
        <button onClick={() => loginWithOAuth('github')}>Entrar com GitHub</button>
      </div>

      <p style={{ marginTop: 20 }}>
        Nao tem conta? <Link href="/register">Criar conta</Link>
      </p>
    </div>
  );
}

Pagina de Registro

// app/register/page.tsx
'use client';

import { useState } from 'react';
import { useNiceLogin } from 'nicelogin-nextjs/client';
import { useRouter } from 'next/navigation';
import Link from 'next/link';

export default function RegisterPage() {
  const router = useRouter();
  const { register, isLoading } = useNiceLogin();
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');
  const [error, setError] = useState('');

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setError('');

    if (password !== confirmPassword) {
      setError('As senhas nao coincidem');
      return;
    }

    try {
      await register(email, password);
      router.push('/dashboard');
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Erro ao criar conta');
    }
  };

  return (
    <div style={{ maxWidth: 400, margin: '100px auto', padding: 20 }}>
      <h1>Criar Conta</h1>

      {error && <p style={{ color: 'red' }}>{error}</p>}

      <form onSubmit={handleSubmit}>
        <div style={{ marginBottom: 15 }}>
          <label>Email</label>
          <input
            type="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            required
            style={{ width: '100%', padding: 8 }}
          />
        </div>

        <div style={{ marginBottom: 15 }}>
          <label>Senha</label>
          <input
            type="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
            required
            minLength={8}
            style={{ width: '100%', padding: 8 }}
          />
        </div>

        <div style={{ marginBottom: 15 }}>
          <label>Confirmar Senha</label>
          <input
            type="password"
            value={confirmPassword}
            onChange={(e) => setConfirmPassword(e.target.value)}
            required
            style={{ width: '100%', padding: 8 }}
          />
        </div>

        <button type="submit" disabled={isLoading} style={{ width: '100%', padding: 10 }}>
          {isLoading ? 'Criando...' : 'Criar Conta'}
        </button>
      </form>

      <p style={{ marginTop: 20 }}>
        Ja tem conta? <Link href="/login">Fazer login</Link>
      </p>
    </div>
  );
}

Pagina Dashboard (Protegida)

// app/dashboard/page.tsx
import { redirect } from 'next/navigation';
import { getSession, initializeConfig } from 'nicelogin-nextjs';
import LogoutButton from './LogoutButton';

export default async function DashboardPage() {
  initializeConfig({ apiKey: process.env.NEXT_PUBLIC_NICELOGIN_API_KEY! });

  const session = await getSession();
  if (!session) {
    redirect('/login');
  }

  return (
    <div style={{ maxWidth: 600, margin: '50px auto', padding: 20 }}>
      <h1>Dashboard</h1>
      <p>Bem-vindo, {session.user.email}!</p>
      <p>User ID: {session.user.id}</p>
      <p>Company ID: {session.user.companyId}</p>
      <LogoutButton />
    </div>
  );
}
// app/dashboard/LogoutButton.tsx
'use client';

import { useNiceLogin } from 'nicelogin-nextjs/client';
import { useRouter } from 'next/navigation';

export default function LogoutButton() {
  const router = useRouter();
  const { logout } = useNiceLogin();

  const handleLogout = async () => {
    await logout();
    router.push('/login');
  };

  return (
    <button onClick={handleLogout} style={{ marginTop: 20, padding: 10 }}>
      Sair
    </button>
  );
}

Licenca

MIT