SDK ve Kütüphane Örnekleri
Atlantic ID entegrasyonu için popüler dillerde hazır kod örnekleri.
JavaScript / TypeScript
Node.js (Backend)
Kurulum
npm install openid-client express express-session
Tam Örnek
const express = require('express');
const session = require('express-session');
const { Issuer, generators } = require('openid-client');
const app = express();
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: { secure: true, httpOnly: true }
}));
// Atlantic ID Client Setup
let atlanticIdClient;
(async () => {
const issuer = await Issuer.discover('https://id.codeatlantis.com');
atlanticIdClient = new issuer.Client({
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET,
redirect_uris: ['https://myapp.com/auth/callback'],
response_types: ['code']
});
})();
// Login Route
app.get('/auth/login', (req, res) => {
const codeVerifier = generators.codeVerifier();
const codeChallenge = generators.codeChallenge(codeVerifier);
const state = generators.state();
const nonce = generators.nonce();
req.session.codeVerifier = codeVerifier;
req.session.state = state;
req.session.nonce = nonce;
const authUrl = atlanticIdClient.authorizationUrl({
scope: 'openid profile email',
code_challenge: codeChallenge,
code_challenge_method: 'S256',
state,
nonce
});
res.redirect(authUrl);
});
// Callback Route
app.get('/auth/callback', async (req, res) => {
try {
const params = atlanticIdClient.callbackParams(req);
const tokenSet = await atlanticIdClient.callback(
'https://myapp.com/auth/callback',
params,
{
code_verifier: req.session.codeVerifier,
state: req.session.state,
nonce: req.session.nonce
}
);
const userinfo = await atlanticIdClient.userinfo(tokenSet.access_token);
req.session.user = {
id: userinfo.sub,
email: userinfo.email,
name: userinfo.name
};
req.session.accessToken = tokenSet.access_token;
req.session.refreshToken = tokenSet.refresh_token;
res.redirect('/dashboard');
} catch (error) {
console.error('Auth failed:', error);
res.redirect('/login?error=auth_failed');
}
});
// Protected Route
app.get('/dashboard', (req, res) => {
if (!req.session.user) {
return res.redirect('/login');
}
res.json({ user: req.session.user });
});
// Logout
app.post('/auth/logout', (req, res) => {
req.session.destroy();
res.redirect('/');
});
app.listen(3000);
React (Frontend SPA)
Kurulum
npm install react-router-dom
Hook: useAuth.js
import { useState, useEffect, createContext, useContext } from 'react';
const AuthContext = createContext();
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Check for callback
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
if (code) {
handleCallback(code);
} else {
checkSession();
}
}, []);
async function handleCallback(code) {
try {
const verifier = sessionStorage.getItem('pkce_verifier');
const state = params.get('state');
const storedState = sessionStorage.getItem('oauth_state');
if (state !== storedState) {
throw new Error('State mismatch');
}
// Backend'e gönder
const response = await fetch('/api/auth/callback', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code, code_verifier: verifier })
});
const { user } = await response.json();
setUser(user);
sessionStorage.removeItem('pkce_verifier');
sessionStorage.removeItem('oauth_state');
window.history.replaceState({}, '', '/');
} catch (error) {
console.error('Auth failed:', error);
} finally {
setLoading(false);
}
}
async function checkSession() {
try {
const response = await fetch('/api/auth/me');
if (response.ok) {
const { user } = await response.json();
setUser(user);
}
} finally {
setLoading(false);
}
}
async function login() {
const { verifier, challenge } = await generatePKCE();
const state = generateRandomString();
sessionStorage.setItem('pkce_verifier', verifier);
sessionStorage.setItem('oauth_state', state);
const authUrl = new URL('https://id.codeatlantis.com/oauth/authorize');
authUrl.searchParams.set('client_id', process.env.REACT_APP_CLIENT_ID);
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('scope', 'openid profile email');
authUrl.searchParams.set('redirect_uri', window.location.origin + '/callback');
authUrl.searchParams.set('state', state);
authUrl.searchParams.set('code_challenge', challenge);
authUrl.searchParams.set('code_challenge_method', 'S256');
window.location.href = authUrl.toString();
}
async function logout() {
await fetch('/api/auth/logout', { method: 'POST' });
setUser(null);
}
return (
<AuthContext.Provider value={{ user, loading, login, logout }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
return useContext(AuthContext);
}
// Helper functions
async function generatePKCE() {
const verifier = generateCodeVerifier();
const challenge = await generateCodeChallenge(verifier);
return { verifier, challenge };
}
function generateCodeVerifier() {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return base64UrlEncode(array);
}
async function generateCodeChallenge(verifier) {
const encoder = new TextEncoder();
const data = encoder.encode(verifier);
const hash = await crypto.subtle.digest('SHA-256', data);
return base64UrlEncode(new Uint8Array(hash));
}
function base64UrlEncode(buffer) {
return btoa(String.fromCharCode(...buffer))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
function generateRandomString() {
return base64UrlEncode(crypto.getRandomValues(new Uint8Array(16)));
}
Kullanım
import { AuthProvider, useAuth } from './useAuth';
function App() {
return (
<AuthProvider>
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<ProtectedRoute><Dashboard /></ProtectedRoute>} />
</Routes>
</Router>
</AuthProvider>
);
}
function ProtectedRoute({ children }) {
const { user, loading } = useAuth();
if (loading) return <div>Loading...</div>;
if (!user) return <Navigate to="/" />;
return children;
}
function Home() {
const { user, login } = useAuth();
if (user) return <Navigate to="/dashboard" />;
return (
<div>
<h1>Welcome</h1>
<button onClick={login}>Login with Atlantic ID</button>
</div>
);
}
function Dashboard() {
const { user, logout } = useAuth();
return (
<div>
<h1>Welcome, {user.name}!</h1>
<p>Email: {user.email}</p>
<button onClick={logout}>Logout</button>
</div>
);
}
PHP
Laravel
Kurulum
composer require league/oauth2-client
Config (config/services.php)
return [
'atlantic_id' => [
'client_id' => env('ATLANTIC_ID_CLIENT_ID'),
'client_secret' => env('ATLANTIC_ID_CLIENT_SECRET'),
'redirect' => env('ATLANTIC_ID_REDIRECT_URI'),
],
];
Controller
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use League\OAuth2\Client\Provider\GenericProvider;
class AuthController extends Controller
{
private function getProvider()
{
return new GenericProvider([
'clientId' => config('services.atlantic_id.client_id'),
'clientSecret' => config('services.atlantic_id.client_secret'),
'redirectUri' => config('services.atlantic_id.redirect'),
'urlAuthorize' => 'https://id.codeatlantis.com/oauth/authorize',
'urlAccessToken' => 'https://id.codeatlantis.com/oauth/token',
'urlResourceOwnerDetails' => 'https://id.codeatlantis.com/oauth/userinfo',
'scopes' => 'openid profile email',
]);
}
public function login(Request $request)
{
$provider = $this->getProvider();
// PKCE
$codeVerifier = bin2hex(random_bytes(32));
$codeChallenge = rtrim(strtr(base64_encode(hash('sha256', $codeVerifier, true)), '+/', '-_'), '=');
session([
'oauth2_code_verifier' => $codeVerifier,
'oauth2_state' => $provider->getState(),
]);
$authUrl = $provider->getAuthorizationUrl([
'code_challenge' => $codeChallenge,
'code_challenge_method' => 'S256',
]);
return redirect($authUrl);
}
public function callback(Request $request)
{
$provider = $this->getProvider();
if ($request->get('state') !== session('oauth2_state')) {
session()->forget(['oauth2_state', 'oauth2_code_verifier']);
return redirect('/')->withErrors(['error' => 'Invalid state']);
}
try {
$accessToken = $provider->getAccessToken('authorization_code', [
'code' => $request->get('code'),
'code_verifier' => session('oauth2_code_verifier'),
]);
$resourceOwner = $provider->getResourceOwner($accessToken);
$userData = $resourceOwner->toArray();
// Create or update user
$user = \App\Models\User::updateOrCreate(
['atlantic_id' => $userData['sub']],
[
'name' => $userData['name'],
'email' => $userData['email'],
'email_verified_at' => now(),
]
);
auth()->login($user);
session()->forget(['oauth2_state', 'oauth2_code_verifier']);
return redirect('/dashboard');
} catch (\Exception $e) {
return redirect('/')->withErrors(['error' => 'Authentication failed']);
}
}
public function logout()
{
auth()->logout();
return redirect('/');
}
}
Routes (routes/web.php)
Route::get('/auth/login', [AuthController::class, 'login'])->name('auth.login');
Route::get('/auth/callback', [AuthController::class, 'callback'])->name('auth.callback');
Route::post('/auth/logout', [AuthController::class, 'logout'])->name('auth.logout');
Python
Django
Kurulum
pip install authlib requests
views.py
from django.shortcuts import redirect
from django.http import JsonResponse
from authlib.integrations.django_client import OAuth
from django.contrib.auth import login, logout
from django.contrib.auth.decorators import login_required
import os
oauth = OAuth()
oauth.register(
name='atlantic_id',
client_id=os.getenv('ATLANTIC_ID_CLIENT_ID'),
client_secret=os.getenv('ATLANTIC_ID_CLIENT_SECRET'),
server_metadata_url='https://id.codeatlantis.com/.well-known/openid-configuration',
client_kwargs={
'scope': 'openid profile email',
'code_challenge_method': 'S256',
}
)
def login_view(request):
redirect_uri = request.build_absolute_uri('/auth/callback')
return oauth.atlantic_id.authorize_redirect(request, redirect_uri)
def callback_view(request):
try:
token = oauth.atlantic_id.authorize_access_token(request)
userinfo = token['userinfo']
# Create or get user
user, created = User.objects.get_or_create(
username=userinfo['sub'],
defaults={
'email': userinfo['email'],
'first_name': userinfo['name'].split()[0] if userinfo.get('name') else '',
}
)
login(request, user)
return redirect('/dashboard')
except Exception as e:
return redirect('/?error=auth_failed')
@login_required
def logout_view(request):
logout(request)
return redirect('/')
urls.py
urlpatterns = [
path('auth/login', login_view, name='login'),
path('auth/callback', callback_view, name='callback'),
path('auth/logout', logout_view, name='logout'),
]
Go
Fiber Framework
Kurulum
go get github.com/gofiber/fiber/v2
go get github.com/coreos/go-oidc/v3/oidc
go get golang.org/x/oauth2
main.go
package main
import (
"context"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"log"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/session"
"golang.org/x/oauth2"
)
var (
config *oauth2.Config
verifier *oidc.IDTokenVerifier
store *session.Store
)
func init() {
ctx := context.Background()
provider, _ := oidc.NewProvider(ctx, "https://id.codeatlantis.com")
config = &oauth2.Config{
ClientID: os.Getenv("CLIENT_ID"),
ClientSecret: os.Getenv("CLIENT_SECRET"),
RedirectURL: "https://myapp.com/auth/callback",
Endpoint: provider.Endpoint(),
Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
}
verifier = provider.Verifier(&oidc.Config{ClientID: config.ClientID})
store = session.New()
}
func main() {
app := fiber.New()
app.Get("/auth/login", login)
app.Get("/auth/callback", callback)
app.Post("/auth/logout", logout)
log.Fatal(app.Listen(":3000"))
}
func login(c *fiber.Ctx) error {
sess, _ := store.Get(c)
// PKCE
verifier := generateCodeVerifier()
challenge := generateCodeChallenge(verifier)
state := generateRandomString(32)
sess.Set("code_verifier", verifier)
sess.Set("state", state)
sess.Save()
authURL := config.AuthCodeURL(state,
oauth2.SetAuthURLParam("code_challenge", challenge),
oauth2.SetAuthURLParam("code_challenge_method", "S256"),
)
return c.Redirect(authURL)
}
func callback(c *fiber.Ctx) error {
sess, _ := store.Get(c)
code := c.Query("code")
state := c.Query("state")
storedState := sess.Get("state").(string)
if state != storedState {
return c.SendStatus(400)
}
verifier := sess.Get("code_verifier").(string)
token, err := config.Exchange(context.Background(), code,
oauth2.SetAuthURLParam("code_verifier", verifier),
)
if err != nil {
return c.SendStatus(500)
}
// Verify ID Token
rawIDToken := token.Extra("id_token").(string)
idToken, err := verifier.Verify(context.Background(), rawIDToken)
if err != nil {
return c.SendStatus(500)
}
var claims struct {
Sub string `json:"sub"`
Email string `json:"email"`
Name string `json:"name"`
}
idToken.Claims(&claims)
sess.Set("user", claims)
sess.Delete("code_verifier")
sess.Delete("state")
sess.Save()
return c.Redirect("/dashboard")
}
func logout(c *fiber.Ctx) error {
sess, _ := store.Get(c)
sess.Destroy()
return c.Redirect("/")
}
func generateCodeVerifier() string {
b := make([]byte, 32)
rand.Read(b)
return base64.RawURLEncoding.EncodeToString(b)
}
func generateCodeChallenge(verifier string) string {
h := sha256.New()
h.Write([]byte(verifier))
return base64.RawURLEncoding.EncodeToString(h.Sum(nil))
}
func generateRandomString(length int) string {
b := make([]byte, length)
rand.Read(b)
return base64.RawURLEncoding.EncodeToString(b)
}
Tüm örnekler GitHub'da: github.com/codeatlantis/atlantic-id-examples
İlgili: Getting Started, API Reference