Skip to content

Commit 7d3fdd8

Browse files
chuckcarpenterRobbieTheWagner
authored andcommitted
Migrate from AWS Cognito to Supabase OTP authentication
- Replace Cognito with Supabase for auth (email OTP flow) - Add new supabase service with OTP methods (signInWithOtp, verifyOtp) - Add supabase authenticator for ember-simple-auth - Replace JSONAPI remote source with Supabase data source - Simplify login flow: single 2-step OTP process for new/existing users - Remove password-related flows (forgot-password, register-confirm) - Update tests for new OTP authentication flow - Add migration documentation BREAKING: Requires SUPABASE_URL and SUPABASE_ANON_KEY env vars
1 parent edb062d commit 7d3fdd8

26 files changed

Lines changed: 1421 additions & 3381 deletions

File tree

app/authenticators/cognito.js

Lines changed: 0 additions & 48 deletions
This file was deleted.

app/authenticators/supabase.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { getOwner } from '@ember/owner';
2+
3+
import BaseAuthenticator from 'ember-simple-auth/authenticators/base';
4+
5+
import type SupabaseService from '../services/supabase.ts';
6+
7+
export interface SupabaseAuthData {
8+
userId: string;
9+
email: string;
10+
accessToken: string;
11+
refreshToken: string;
12+
expiresAt: number;
13+
}
14+
15+
export interface OtpCredentials {
16+
email: string;
17+
token: string;
18+
}
19+
20+
export default class SupabaseAuthenticator extends BaseAuthenticator {
21+
get supabase(): SupabaseService {
22+
return getOwner(this)?.lookup('service:supabase') as SupabaseService;
23+
}
24+
25+
/**
26+
* Authenticate with OTP code.
27+
* Called when user submits the verification code.
28+
*/
29+
async authenticate(credentials: OtpCredentials): Promise<SupabaseAuthData> {
30+
const { email, token } = credentials;
31+
32+
const { user, session } = await this.supabase.verifyOtp(email, token);
33+
34+
return {
35+
userId: user.id,
36+
email: user.email ?? email,
37+
accessToken: session.access_token,
38+
refreshToken: session.refresh_token,
39+
expiresAt: session.expires_at ?? 0,
40+
};
41+
}
42+
43+
/**
44+
* Restore session from Supabase's persisted storage.
45+
* Called on app startup to check if user is still logged in.
46+
*/
47+
async restore(_data: SupabaseAuthData): Promise<SupabaseAuthData> {
48+
const session = await this.supabase.getSession();
49+
50+
if (!session) {
51+
throw new Error('No active session');
52+
}
53+
54+
const user = await this.supabase.getUser();
55+
56+
if (!user) {
57+
throw new Error('No authenticated user');
58+
}
59+
60+
return {
61+
userId: user.id,
62+
email: user.email ?? '',
63+
accessToken: session.access_token,
64+
refreshToken: session.refresh_token,
65+
expiresAt: session.expires_at ?? 0,
66+
};
67+
}
68+
69+
/**
70+
* Invalidate session (logout).
71+
*/
72+
async invalidate(): Promise<void> {
73+
await this.supabase.signOut();
74+
}
75+
}

app/components/forgot-password.gts

Lines changed: 0 additions & 167 deletions
This file was deleted.

0 commit comments

Comments
 (0)