Supabase 트러블 슈팅 - Team-HGD/SniffMEET GitHub Wiki
- JWT, Refresh 토큰과 세션의 개념이 잘 정립되지 않은 상태
- 특히 익명 계정을 생성은 했는데, 이 생성한 계정을 어떻게 쓰는가? 에 대한 해결 과정이 필요했다.
- SDK를 뜯어보니 토큰과 현재 유저 정보를 저장하고 있는 것을 SupabaseSession이라고 하는 것 같다.
- 생성, 복원, 갱신 로직이 굉장히 밀접하게 연관되어 있고 특히 복원과 갱신 로직은 파고들수록 비슷해진다.
- 앱을 다운받고 처음 실행했을 때와, 앱을 다시 실행했을 때의 동작 차이를 확실하게 구분할 수 있어야 한다.
- 익명 로그인을 했으니, 키체인에 저장된 세션의 유무로 파악할 수 있지 않을까?
- 일단 시점에 따른 Supabase Session의 상태를 표로 시각화했다.
최초로 앱 실행 | 앱 다시 실행 | 실행 중 | |
---|---|---|---|
라이브 세션 | X | X | O |
유저 정보 | X | X | O |
키체인 저장 토큰 | X | O | O |
- 키체인에 토큰이 저장되어 있는지 여부로 앱이 실행될 때, 세션 복원을 해야하는지 아니면 익명 로그인을 해야하는지 알 수 있다.
- 처음에 복원을 시도하고 실패하면 익명 로그인, 복원이 성공하면 그대로 복원하고 세션 객체를 생성하면 된다.
갱신 로직 생성
- 현재 세션에서
Refresh Token
을 가져온다. -
Refresh Token
으로 네트워크에JWT 토큰
갱신을 요청한다. - 새로 받아온 토큰으로 현재 토큰을 업데이트 한다.
복원 로직 생성
- 키체인에서 토큰을 가져와서 세션을 업데이트 한다. (만료 여부랑 상관없이)
- 토큰이 만료되었는지 확인한다. 토큰 만료 시점을 가지고 있으므로 서버와 연결 없이 바로 확인할 수 있다.
- 만료된 토큰이라면 갱신을 요청한다.
- 만료되지 않은 토큰이라면 서버에 유저 정보를 요청한다. (키체인에는 유저 정보가 없으므로)
- 새로 받아온 토큰, 유저 정보로 세션 객체를 생성한다.
유저 정보만 따로 서버에 요청할 수는 있지만, 실제로 갱신을 수행했을 때 토큰 뿐만 아니라 세션 전체 내용이 응답으로 오게 되는 것을 알게 됨.
수정된 복원 로직
- 키체인에서 토큰을 가져와서 세션을 업데이트한다. (만료 여부랑 상관없이)
- (만료 여부랑 상관없이) 바로 세션 갱신을 요청하여 서버에서 세션을 받아와서 세션 객체를 생성한다.
- Public Scheme에 있는 테이블을
anon-key
로는 접근 가능하나,anon-user
(익명 유저)의 JWT 토큰으로는 접근하지 못하는 문제 발생 - anon-key는 공개키라서 인터넷에 공개해도 되는 키고, anon-user의 JWT 토큰은 사용자 인증 정보가 담겨있어서 보안이 필요한 키임
-
anon-key
,anon-role
,anon-user
의 차이-
anon-key
를 이용한 접근을anon-role
이라고 하고, -
anon-user
는 이메일 주소, 전화번호 등을 등록하지 않은 유저를 말함. role 자체는authenticated-role
이다.
-
- 익명 유저가 접근했을 때
200 OK
가 뜨지만, 실제론 아무런 값을 가져오지 못함 → 접근 권한 자체는 존재하지만RLS
에서 막힌 것을 유추할 수 있음 -
anon-role
과authenticated-role
은 상하 관계가 아니고 서로 독립된 롤이다.
- SQL 쿼리를 통해서 RLS 설정 →
authenticated-role
인 유저만 접근할 수 있는 테이블로
CREATE policy "Authenticated users can read"
ON "public"."hgdtest"
TO public
USING (
(auth.role() = 'authenticated'::text)
);
RLS를 설정한 이후에는 테이블의 데이터를 잘 받아올 수 있었다.
→ authenticated-role
이 anon-role
을 포함하지 않는 사실을 알 수 있었다.
→ RLS에 걸린 것은 응답에 실패한것으로 처리되지 않는다.
추가적으로,
아무런 RLS 정책이 설정되어 있지 않으면 기본적으로 모든 접근에 배타적으로 된다. 즉 Public 테이블이더라도 RLS가 켜져있는 상태에서 아무런 정책이 없다면, 사실상 Private 테이블이 된다는 것을 알게 됨.
-
다른 작업을 하고 다시 확인을 해 보니 JWT 토큰의 수명이 매우 짧다는 것을 알게 됨. 현재 서버에서 지정된 시간은 3600초(1시간)임을 확인가능
-
그래도 테이블 자체의 접근 권한을 설정하는 것은 RLS보다는 DCL을 쓰는게 낫다.
- role 단위 지정이 가능함.
- RLS에 걸리는 것은 응답 코드가
200 OK
가 되고 데이터를 안 불러오는 방식이 되지만, DCL로 지정한 접근 권한에 걸리는 것은401 Unauthorized
에러가 뜸.
GRANT SELECT, INSERT, UPDATE, DELETE ON public.mate_list TO "Authenticated-role";
- 저희도 서버 분리했어요… SniffMEET-Test랑 SniffMEET으로…
- (저희 프로젝트 세션엔 없지만 실제 Supabase)세션에 포함되어있는
user_metadata
도 처음에 많이 고려했었던 친구인데요. 쓰지 않게된 이유는 아래와 같습니다!- 일단 장점으로는 테이블이 아닌 바로 json 파일로 저장되어서 매우 불러오기 편함
- 가장 큰 단점으로는 다른 유저가 접근을 못함. 내 정보는 내가 이미 로컬에도 가지고 있는데…
- 그리고 혜민님이 Storage 관련 한 것도 넣을만한거 있을텐데 이미 하셨겠죠? 버켓 구조같은거 고민했던거…