Uwierzytelnianie z Sign In With Google


Tworzenie konta przez nowych użytkowników i logowanie się do systemu zazwyczaj wymaga podania co najmniej adresu email i hasła. Alternatywą dla tego typu rozwiązań jest dodatnie uwierzytelniania za pomocą zewnętrznych serwisów, które poświadczą wiarygodność użytkownika. Jedną z najbardziej popularnych opcji jest Sign In With Google
i na tej usłudze skupimy się w tym artykule.
Do stworzenia prostej aplikacji wykorzystamy Next.js, Prismę i SQLite, ale będzie to o tyle uniwersalne, że spokojnie możesz wykorzystać do tego inne narzędzia.
Czym jest Sign In With Google i jakie korzyści daje
Sign In With Google
w skrócie, ma na celu szybsze przeprowadzenie procesu uwierzytelniania w twojej aplikacji, na co składa się zarówno tworzenie nowego konta, jak i logowanie przez już istniejącego użytkownika. Takie rozwiązanie jest niezmiernie wygodne, ponieważ użytkownik nie musi wypełniać formularzu do rejestracji lub logowania, gdyż jest to zastępowane przez jeden guzik Zaloguj się przez Google
. Zamiast inputów do wpisywania hasła i adresu email wyświetlamy taki przycisk:

W kontekście formularza rejestracji może się zdarzyć, że będziemy wymagać od użytkownika podania dodatkowych danych (np. adres lub nr telefonu), więc w tym przypadku po uwierzytelnianiu przez Sign In With Google
wyświetlimy dodatkowy w formularz, na którym zbierzemy dodatkowe informacje.
Główne zalety tego rozwiązania:
- otrzymujemy zaufane i bezpieczne źródło uwierzytelniania użytkowników
- dostęp do danych osobistych jak email czy imię i nazwisko na etapie tworzenia konta
- wygoda użytkowników, co przekłada się na większą konwersję na stronie
Jak to działa?
Mechanizm działania nie jest skomplikowany i cały proces można opisać w kilku krokach:
- Użytkownik klika w guzik "Zaloguj się przez Google"
- Wyświetlany jest ekran zgód, na którym użytkownik potwierdza chęć uwierzytelnienia i przekazania danych profilowych do naszej aplikacji
- W odpowiedzi dostajemy
ID token
, który zawiera m. in. nazwę i email użytkownika - Token wysyłamy do aplikacji backendowej, gdzie będzie on weryfikowany
- Po poprawnej weryfikacji dodajemy nowego użytkownika do bazy danych (jeżeli nie istnieje), tworzymy token JWT i zwracamy go do aplikacji frontendowej
- Tak otrzymany token możemy przechowywać w Local Storage i wykorzystać do autoryzacji
Punkt 5 i 6 nie musi wyglądać zawsze tak samo i zależy to od przyjętego sposobu uwierzytelniania w aplikacji (zamiast JWT mogą być sesje i cookies). W tym artykule przyjęliśmy prosty system tworzenia tokenów JWT dla zalogowanych użytkowników.
Stworzenie prostej aplikacji do uwierzytelniania
Do tyle jeżeli chodzi o teorię! Przejdźmy teraz do napisania aplikacji, w której zobaczymy, jak w kilku krokach zaimplementować Sign In With Google
.
Założenie konta w Google API
W tym kroku stworzymy ekran zgód oraz otrzymamy unikalny klucz Client ID
, który jest niezbędny do dodania przycisku logowania. Posłuży nam w inicjowaniu klienta na froncie oraz przy walidacji ID token
na backendzie.
Tworzenie zgód
- Wchodzimy na stronę https://console.developers.google.com/apis
- Przechodzimy do zakładki OAuth consent screen i ustawiamy wartości
- Name => Sign In With Google Test App
- Support email & Developer contact information => podajemy nasz adres email
- Wybieramy UserType => External
- Klikamy Save and continue i przechodzmy cały formularz z domyślnymi wartościami
Tworzenie danych logowania
- Przechodzimy do zakładki Credentials
- Wybieramy Utwórz dane logowania => Identyfikator klienta OAuth
- Wybieramy Application type => Web application
- W sekcji Authorized JavaScript origins dodajemy dwa rekordy:
- http://localhost
- http://localhost:3000
- Klikamy Create
Aplikacja w Next.js
1. Zacznijmy od postawienia aplikacji (nazwijmy ją sign-in-with-google-app
):
npx create-next-app@latest --ts
Teraz spróbujmy ją uruchomić:
cd sign-in-with-google-app
npm run dev
Aplikacja powinna odpalić się w przeglądarce na porcie 3000
.
2. Następnym krokiem jest zainicjowanie klienta Sign In With Google i dodanie przycisku logowania na ekranie:
// index.tsx
import Script from "next/script";
export default function Home() {
// inicjujemy klienta Sign In With Google
const initGoogleSignIn = () => {
google.accounts.id.initialize({
// dodajemy wygnenerowany wcześniej Client ID z Google API
client_id: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID!,
// callback wywoływany po zalogowaniu się przez użytkownika
callback: handleCredentialResponse,
});
// renderujemy przycisk logowania
google.accounts.id.renderButton(
document.getElementById("googleSignInBtnWrapper")!,
{ type: "standard", shape: "pill" },
);
};
const handleCredentialResponse = async (
credentials: google.accounts.id.CredentialResponse,
) => {};
// ładujemy skrypt i po jego wczytaniu inicjujemy klienta Sign In With Google
return (
<>
<div id="googleSignInBtnWrapper" />
<Script
src="https://accounts.google.com/gsi/client"
onReady={initGoogleSignIn}
/>
</>
);
}
Musimy jeszcze zainstalować odpowiednie typy dla google.accounts
:
npm install --save @types/google.accounts
3. Gdy już mamy widoczny nasz przycisk na ekranie, możemy zabrać się za stworzenie prostego API, które będzie umożliwiało zalogowanie się i przechowywanie użytkowników w bazie danych. Do tego celu wykorzystamy narzędzie Prima:
npm install prisma --save-dev
npx prisma init --datasource-provider sqlite
4. Teraz dodajemy model User
, który Prisma przemapuję na odpowiednią encję w bazie danych:
// prisma/schema.prisma
...
model User {
id Int @id @default(autoincrement())
email String @unique
authProviderId String @unique
}
5. Następnie uruchamiamy migrację, która doda tabelę User
:
npx prisma migrate dev --name init
6. Pozostaje nam jeszcze dodanie endpointu do logowania użytkownika. Najpierw zainstalujemy niezbędne biblioteki:
npm i google-auth-library jsonwebtoken
npm i --save-dev @types/jsonwebtoken
Teraz możemy dodać logikę, która będzie odpowiadać za weryfikowanie ID token
zalogowanego użytkownika i zwracać token JWT, który później możemy wykorzystać do autoryzacji.
// pages/api/login.ts
import type { NextApiRequest, NextApiResponse } from "next";
import { PrismaClient } from "@prisma/client";
import { OAuth2Client, TokenPayload } from "google-auth-library";
import jwt from "jsonwebtoken";
// inicjujemy klienta Prismy i OAuth2
const prisma = new PrismaClient();
const authClient = new OAuth2Client();
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
if (req.method === "POST") {
const { idToken } = req.body;
try {
// weryfikujemy czy token ID jest na pewno poprawny
const payload = await verifyIdToken(idToken);
const userId = payload.sub;
const userEmail = payload.email;
let user = await prisma.user.findFirst({
where: {
authProviderId: userId,
},
});
// jeżeli użytkownik nie istnieje, tworzymy go
if (!user) {
user = await prisma.user.create({
data: {
email: userEmail!,
authProviderId: userId,
},
});
}
// generujemy token JWT
const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET!);
res.status(200).json({ token });
} catch (error) {
res.status(401).json({ message: "Login failed" });
}
}
}
async function verifyIdToken(idToken: string): Promise<TokenPayload> {
// ta walidacja jest rekomendowana przez Google dla zwiększenia bezpieczeństwa,
// ponieważ ID token mógł zostać zmieniony po stronie klienta
const ticket = await authClient.verifyIdToken({
idToken: idToken,
audience: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID,
});
const payload = ticket.getPayload();
if (!payload || !payload.sub || !payload.email) {
throw new Error("Invalid token");
}
return payload;
}
7. Na koniec pozostaje nam tylko dodanie logiki do metody handleCredentialResponse
, która wywoła endpoint /api/login
:
export default function Home() {
...
const handleCredentialResponse = async (
credentials: google.accounts.id.CredentialResponse,
) => {
const response = await fetch("/api/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ idToken: credentials.credential }),
});
const data = await response.json();
console.log(data);
};
...
}
Podsumowanie
Sign In With Google zwiększa komfort logowania się użytkownika na naszej stronie, a implementacja tego — jak mogliśmy się przekonać — nie jest zbyt złożona. W zaledwie kilku krokach możemy dodać tę wygodną formę uwierzytelniania w naszej aplikacji.
Link do kodu: https://github.com/folt3k/sign-in-with-google-test-app