👉🏻 회원가입 및 로그인과 관련된 기능입니다.
These are features related to sign-up and login.
👉🏻 myapp39에서는 이전에 완료되지 않았던 로그인 기능을 완성합니다.
In myapp39, we complete the login functionality that was not finished previously.
👉🏻 전체 코드는 깃허브에서 확인 할 수 있습니다.
You can find the full code on GitHub.
https://github.com/gideonslife01/flm-nextjs
📁 전체 프로젝트 구조 / Overall Project Structure
myapp project/
├── app/ (Next.js App Router)
│ ├── .well-known/webfinger/route.ts -> webfinger
│ ├── api/follow/route.ts -> Follow API(temporary)
│ ├── api/announce/route.ts -> Boost(Announcement)
│ ├── api/like/route.ts. -> Like API
│ ├── api/posts/route.ts -> Writing API
│ ├── api/timeline/route.ts -> Timeline API
│ ├── api/v1/instance/route.ts -> auth
│ ├── api/v1/apps/route.ts. -> auth
│ ├── api/v1/accounts/verify_credentials/route.ts -> auth
│ ├── api/v1/statuses/route.ts -> Write Post
│ ├── api/v1/timelines/home/route.ts -> timeline
│ ├── oauth/authorize/route.ts -> auth
│ ├── oauth/token/route.ts -> auth
│ ├── api/v1/search/home/route.ts -> search
│ ├── api/v2/search/home/route.ts -> search
│ ├── api/v1/accounts/[id]/followers/route.ts -> followers
│ ├── api/v1/accounts/[id]/following/route.ts -> following
│ ├── api/auth/signup/route.ts -> Signup
│ ├── api/auth/login/route.ts -> Login
│ ├── api/auth/logout/route.ts -> Logout
│ ├── auth/signup/page.tsx -> Signup UI
│ ├── auth/signup/page.tsx -> Login UI
│ ├── users/[username]/
│ │ ├── statuses/[id]/route.ts -> Indivisual Post
│ │ ├── route.ts -> Acotr Information
│ │ ├── followers/route.ts -> Followers List
│ │ ├── following/route.ts -> Following List
│ │ ├── inbox/route.ts -> Inbox
│ │ └── outbox/route.ts -> outbox
│ ├── usersui/[username]/
│ │ ├── page.tsx -> Timeline UI
│ │ └── _components/themes/
│ │ ├── themeex/ThemeexTheme.tsx -> Example Theme
│ │ ├── pinafore/PinaforeTheme.tsx -> Theme 1
│ │ ├── mastodon/MastodonTheme.tsx -> Theme 2
│ │ └── minimal/MinimaltTheme.tsx -> Theme 3
│ ├── layout.tsx, page.tsx, globals.css
│ └── favicon.ico
├── lib/
│ ├── theme.tsx -> Theme Provider
│ ├── watchThemes.ts -> Check real-time theme changes
│ ├── auth.ts -> Authentication, User Management
│ ├── ap.ts -> Follow,Undo,Create,Likes,Announce
│ └── db.ts -> DB connection
├── data/
│ ├── keys/userIDs/ -> private.pem, public.pem(New)
│ └── keys/ -> private.pem, public.pem(legacy)
├── data.sqlite -> Database(1/3)
├── data.sqlite-wal -> Database(2/3)
├── data.sqlite-shm -> Database(3/3)
├── Caddyfile -> https
├── instrumentation.ts -> Background Server
└── package.json
📁 프로젝트 시작 / Project Start
📁 라우트 추가 /. Add Route
✔️ app/api/auth/signup/route.ts – 회원가입 / Signup
✔️ app/api/auth/login/route.ts – 로그인 / Login
✔️ app/auth/login/page.tsx – 로그인 UI / Login UI
✔️ app/auth/signup/page.tsx – 회원가입 UI / Signup UI
✔️ app/api/auth/logout/route.ts – 로그아웃 / Logout
📁 코드수정 / Code Modification
✔️ lib/auth.ts
export function getUsernameFromRequest(req: Request | NextRequest): string | null { ... }
export function getUsernameFromToken(token: string): string | null { ... }
✔️ app/api/v1/instance/route.ts
— OPTIONS함수 제거(middleware.ts에서 처리)
Remove OPTIONS function (handled in middleware.ts)
// ✅ myapp39 - app/api/v1/instance/route.ts - middleware가! CORS 처리!하니까! 깔끔!
import { NextResponse } from 'next/server';
const DOMAIN = process.env.DOMAIN || 'aloy-horizon.duckdns.org';
export async function GET() {
return NextResponse.json({
uri: `https://${DOMAIN}`,
title: 'Aloy Horizon',
short_description: 'My ActivityPub server!',
description: 'My own Fediverse server running Next.js',
email: 'admin@aloy-horizon.duckdns.org',
version: '4.3.0 (compatible; Aloy Horizon 1.0)',
urls: {
streaming_api: `wss://${DOMAIN}`
},
stats: {
user_count: 1,
status_count: 100,
domain_count: 1000
},
thumbnail: `https://${DOMAIN}/icon.png`,
languages: ['en', 'ko'],
registrations: true,
approval_required: false,
invites_enabled: false,
configuration: {
statuses: {
max_characters: 500,
max_media_attachments: 4
}
},
rules: []
});
}
// OPTIONS함수 제거 middleware.ts에서 처리
// Remove OPTIONS function, handle in middleware.ts
✔️ app/oauth/authorize/route.ts – localhost:3000
... ...
const DOMAIN = process.env.DOMAIN || 'aloy-horizon.duckdns.org';
//const DOMAIN = 'aloy-horizon.duckdns.org';
const ORIGIN = `https://${DOMAIN}`;
... ...
export async function GET(req: Request) {
... ...
// ✅ myapp39 - 로그인 체크 / login check
const username = getUsernameFromCookie(req);
... ...
// ✅ for CORS error
if (!username) {
const loginUrl = new URL('/auth/login', ORIGIN);
const realNextUrl = `${ORIGIN}${url.pathname}${url.search}`;
loginUrl.searchParams.set('next', realNextUrl);
return NextResponse.redirect(loginUrl.toString());
}
... ...
}
✔️ caddyfile
aloy-horizon.duckdns.org {
reverse_proxy localhost:3000 {
header_up Host {host}
header_up X-Real-IP {remote}
header_up X-Forwarded-For {remote}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-Host {host}
}
encode gzip
# CORS는! Next.js가! 처리!하니까! Caddy에서! 헤더! 추가! 금지!
# Next.js handles CORS, so do not add headers in Caddy!
}
✔️ middleware.ts
— Pinafore에서 로그인 하면! ERR_CONNECTION_REFUSED + CORS
Logging in on Pinafore results in ERR_CONNECTION_REFUSED + CORS!
— 모든 요청에 CORS처리 적용 / Apply CORS handling to all requests.
// ✅ myapp39/middleware.ts - CORS 전체 처리 / Global CORS Handling
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(req: NextRequest) {
// ✅ OPTIONS preflight 먼저 처리
// Process the OPTIONS preflight request first.
if (req.method === 'OPTIONS') {
return new NextResponse(null, {
status: 204,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Max-Age': '86400',
},
});
}
// ✅ 일반 요청 / General Request
const res = NextResponse.next();
res.headers.set('Access-Control-Allow-Origin', '*');
res.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
return res;
}
export const config = {
matcher: ['/api/:path*', '/oauth/:path*', '/.well-known/:path*', '/users/:path*'],
};
📁 테스트 / Test
✔️ 터미널 테스트 / Terminal test
# 회원가입 / Signup
curl -X POST https://aloy-horizon.duckdns.org/api/auth/signup \
-H "Content-Type: application/json" \
-d '{"username":"test1","email":"test1@test.com","password":"123456","display_name":"Test1"}'
# Database
sqlite> select username from users;
test1
user1
user2
sqlite>
✔️ 웹사이트 로그인 / Website login
— https://aloy-horizon.duckdns.org/auth/login
1)pinafore에서 로그인 할경우
When logging in on Pinafore

2)웹사이트에서 로그인 할경우
When logging in on the website

✔️ 로그아웃 / Logout

✔️ 웹 회원가입 / Website Signup
— https://aloy-horizon.duckdns.org/auth/signup

요한복음 8장 32절 / John 8:32
“그리고 너희는 진리를 알게 될 것이며, 진리가 너희를 자유롭게 할 것이다.”
“Then you will know the truth ,and the truth will set you free”