API Authentication (iOS ↔ Nextjs ↔ supabase)
2 min readJun 15, 2024
- Getting Supabase session token in iOS
import Supabase
func signInWithApple() {
Supabase.auth.signInWithProvider(.apple, options: SignInWithOAuthOptions(redirectTo: "your-redirect-url")) { result in
switch result {
case .success(let session):
// Save the session access token
if let accessToken = session.accessToken {
storeToken(token: accessToken)
}
case .failure(let error):
print("Error signing in: \(error.localizedDescription)")
}
}
}
func storeToken(token: String) {
let keychain = Keychain(service: "com.yourapp.service")
keychain["supabaseAccessToken"] = token
}
func retrieveToken() -> String? {
let keychain = Keychain(service: "com.yourapp.service")
return keychain["supabaseAccessToken"]
}
2. Include token when calling backend API from iOS
import Alamofire
func makeAuthenticatedRequest() {
guard let token = retrieveToken() else { return }
let headers: HTTPHeaders = [
"Authorization": "Bearer \(token)"
]
AF.request("https://yourapi.vercel.app/endpoint", headers: headers).response { response in
// Handle response
}
}
3. Validate jwt token in Backend middleware
const jwt = require('jsonwebtoken');
const { NextResponse } = require('next/server');
require('dotenv').config();
const supabaseJwtSecret = process.env.SUPABASE_JWT_SECRET;
export async function middleware(req) {
const authHeader = req.headers.get('authorization');
if (!authHeader) {
return NextResponse.json({ message: 'Authorization header missing' }, { status: 401 });
}
const token = authHeader.split(' ')[1];
try {
const user = jwt.verify(token, supabaseJwtSecret);
req.user = user; // Add user to the request object
return NextResponse.next();
} catch (err) {
return NextResponse.json({ message: 'Invalid token' }, { status: 403 });
}
}
export const config = {
matcher: '/api/:path*', // Apply middleware to all API routes
};
c.f. How to find your SUPABASE_JWT_SECRET
> Setting > configuration > API > JWT Settings > JWT Secret
https://supabase.com/dashboard/project/[project id]/settings/api