1.2.10 • Published 1 year ago
link-sso v1.2.10
link-sso
link-sso
는 Next.js 애플리케이션에서 SSO 인증을 쉽게 구현하기 위한 패키지입니다. 이 패키지를 사용하면 통합 SSO 인증을 손쉽게 적용할 수 있습니다.
기능
- SSO 인증 콜백 처리
- 세션 유효성 검증 및 토큰 갱신
설치
pnpm install link-sso
사용 방법
사전설정
supabase에서 table을 생성합니다.
create table
public.oauth_session_tokens (
access_token uuid not null,
refresh_token uuid not null,
user_id uuid not null,
account_id uuid not null,
created_at bigint not null,
available boolean not null default false,
constraint oauth_session_tokens_pkey primary key (access_token, refresh_token),
constraint oauth_access_tokens_accesstoken_id_key unique (access_token),
constraint oauth_session_tokens_refresh_token_key unique (refresh_token)
) tablespace pg_default;
create table
public.accounts (
account_id uuid not null default gen_random_uuid (),
user_id uuid null,
provider text not null,
available boolean not null default false,
created_at timestamp with time zone not null default now(),
provider_user_id uuid not null,
status text null,
constraint account_pkey primary key (account_id)
) tablespace pg_default;
create table
public.users (
user_id uuid not null,
available boolean not null default false,
created_at timestamp with time zone not null default now(),
email text null,
first_name text null,
last_name text null,
account_id uuid[] null,
profile_image text null,
status text null,
constraint profile_pkey primary key (user_id)
) tablespace pg_default;
설정
환경 변수를 설정합니다. .env.local 파일에 다음과 같이 추가합니다:
SSO_LINK_URL=your_sso_provider_url
SSO_LINK_CLIENT_ID=your_client_id
SSO_LINK_SECRET=your_client_secret
SSO_LINK_REDIRECT_URI=your_redirect_uri
SUPABASE_URL=your_supabase_url
SUPABASE_ANON_KEY=your_supabase_anon_key
BASE_URL=your_base_url
COOKIE_PW=your_cookie_password
COOKIE_NAME=your_cookie_name
SSO 인증 콜백 처리
app/api/auth/link/callback.js
파일을 생성하고 다음과 같이 작성합니다:
import { authCallback } from "link-sso";
import { NextResponse } from "next/server";
export async function GET(req) {
try {
const result = await authCallback(req);
console.log(result);
if (result.status === 200) {
return NextResponse.redirect(req.nextUrl.origin + "/app/home");
} else {
return NextResponse.redirect(
req.nextUrl.origin +
`/auth/signin?error=${
result.message ? result.message : "Unknown error"
}`
);
}
} catch (error) {
return NextResponse.redirect(
req.nextUrl.origin +
`/auth/signin?error=${error.message ? error.message : "Unknown error"}`
);
}
}
세션 유효성 검증
app/api/auth/session/validate.js
파일을 생성하고 다음과 같이 작성합니다:
import { validateSession } from "link-sso";
import { NextResponse } from "next/server";
export async function POST(req) {
try {
// validateSession 함수를 호출하고 Next.js의 응답 객체를 전달합니다.
const result = await validateSession(req);
console.log(result);
return NextResponse.json(result);
} catch (error) {
// 에러 처리
return NextResponse.json({ error: error.message });
}
}
로그인 요청
<Link
href={`${process.env.SSO_LINK_URL}/auth/oauth/authorize?oauth=true&response_type=code&client_id=${process.env.SSO_LINK_CLIENT_ID}&scope=id+name+email&redirect_uri=${process.env.SSO_LINK_REDIRECT_URI}`}
className="flex w-full justify-center items-center rounded-md bg-emerald-500 px-3 py-1.5 text-sm font-semibold leading-6 text-black shadow-sm hover:bg-emerald-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-emerald-500 transition duration-200"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 397.80052 450"
className="fill-black mr-2 h-4"
>
<path
className="cls-1"
d="M206.09551,331.73665H191.1868c-24.085,0-43.60961,6.09625-43.60967,13.61639l.00013,91.03057C147.57726,443.90375,167.102,450,191.18693,450h14.90872c24.085,0,43.60967-6.09625,43.60967-13.61639l-.00013-91.03057C249.70519,337.8329,230.18042,331.73665,206.09551,331.73665Z"
/>
<path
className="cls-1"
d="M390.5896,278.26662,246.09313,27.99118a53.50242,53.50242,0,0,0-6.93488-9.867c-.04219-.04777-.08386-.096-.12619-.14357q-.76028-.8526-1.56149-1.67476c-.11687-.12055-.23282-.24194-.35068-.36124q-.6839-.69039-1.39784-1.35683c-.20454-.19246-.40855-.38526-.61571-.57411-.39694-.36091-.80214-.71434-1.21161-1.06469-.29726-.255-.59518-.50836-.8973-.75621-.33919-.27757-.684-.54956-1.03135-.81979q-.57591-.449-1.16108-.88272c-.29359-.216-.59085-.428-.88988-.63881q-.68006-.48-1.37258-.938-.40622-.268-.81887-.52936-.73261-.46458-1.47829-.904c-.15565-.09193-.304-.19135-.46092-.2819-.13636-.07875-.2758-.14706-.41262-.22449q-.68832-.3887-1.38741-.755c-.36458-.19266-.72943-.38348-1.09657-.56689-.36249-.18039-.72786-.35337-1.094-.52536-.48258-.22776-.96567-.45205-1.452-.66427-.224-.09725-.45-.189-.6751-.28322-.62943-.26445-1.2603-.52069-1.89518-.75948-.0605-.02264-.12152-.04338-.18209-.06582A53.38246,53.38246,0,0,0,200.13812.005c-.4121-.01-.82511-.00171-1.23779-.00217-.41269.00046-.8257-.00774-1.2378.00217a53.383,53.383,0,0,0-17.45031,3.3484c-.061.02264-.12258.04351-.18354.06634-.63488.23879-1.26582.495-1.89518.75949-.22481.094-.45035.18571-.674.28282-.48671.21228-.97013.43677-1.453.66467-.366.17193-.73127.34483-1.09362.52516-.36715.18341-.732.37423-1.09658.56689q-.69846.36783-1.38741.755c-.13682.07743-.27626.14574-.41262.22449-.1569.09055-.30527.19-.46092.2819q-.7458.43989-1.47829.904-.41251.26163-.81887.52936-.69345.4578-1.37324.93844-.44775.31556-.8883.63769-.58694.4324-1.16194.88325c-.34759.27049-.69281.54281-1.03227.82058-.30159.24739-.599.50042-.89578.755-.40973.35048-.81513.70417-1.21227,1.06528-.20729.189-.41143.38184-.616.57437q-.71136.66756-1.39646,1.35552c-.11871.12022-.23551.24247-.35324.36393q-.79875.82189-1.559,1.67194c-.043.04842-.0855.09751-.12842.14613a53.50162,53.50162,0,0,0-6.9333,9.865L7.21092,278.26649a53.75607,53.75607,0,1,0,93.10824,53.75607l98.58117-170.7475,98.581,170.74756a53.75605,53.75605,0,1,0,93.10824-53.756Z"
/>
</svg>
테이크업 계정으로 진행하기
</Link>
session 검증
const session = await getIronSessionData();
const valid = await fetch(process.env.BASE_URL + "/api/auth/session/valid", {
method: "POST",
body: JSON.stringify({
session,
}),
}).then((res) => res.json());
(참고) iron session 불러오기
import { getIronSession } from "iron-session";
import { cookies } from "next/headers";
export async function getIronSessionData() {
"use server";
const session = await getIronSession(cookies(), {
password: process.env.COOKIE_PW,
cookieName: process.env.COOKIE_NAME,
});
return session;
}
주의 사항
이 패키지는 Next.js의 서버리스 함수와 함께 사용하기 위해 설계되었습니다. 정확한 구현을 위해서는 Supabase 서비스의 설정이 필요합니다.
지원
문제가 발생하거나 기능 요청이 있는 경우, GitHub Issues를 통해 문의해주세요.
라이선스
이 프로젝트는 MIT 라이선스에 따라 배포됩니다.