File size: 2,691 Bytes
fcbc624
ef0a2d8
 
1f45c3c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fcbc624
 
 
 
 
 
ef0a2d8
1f45c3c
ef0a2d8
1f45c3c
fcbc624
ef0a2d8
 
 
 
1f45c3c
fcbc624
ef0a2d8
 
fcbc624
 
 
 
1f45c3c
fcbc624
 
 
 
 
1f45c3c
fcbc624
 
 
 
 
 
 
ef0a2d8
 
fcbc624
 
 
 
 
 
 
 
 
 
 
 
76d70e1
 
fcbc624
 
ef0a2d8
 
 
1f45c3c
 
fcbc624
ef0a2d8
 
1f45c3c
ef0a2d8
1f45c3c
ef0a2d8
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import { useCallback, useEffect, useState } from 'react';
import { DRIVE_READONLY_SCOPE, GOOGLE_CLIENT_ID } from './config.js';

function decodeJwtPayload(token) {
  try {
    const payload = token.split('.')[1];
    const normalized = payload.replace(/-/g, '+').replace(/_/g, '/');
    const json = decodeURIComponent(
      window
        .atob(normalized)
        .split('')
        .map((char) => `%${`00${char.charCodeAt(0).toString(16)}`.slice(-2)}`)
        .join(''),
    );

    return JSON.parse(json);
  } catch {
    return null;
  }
}

function createNonce() {
  const bytes = new Uint8Array(16);
  window.crypto.getRandomValues(bytes);
  return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('');
}

export function useGoogleDriveAuth() {
  const [idToken, setIdToken] = useState('');
  const [accessToken, setAccessToken] = useState('');
  const [user, setUser] = useState(null);
  const [authReady, setAuthReady] = useState(Boolean(GOOGLE_CLIENT_ID));
  const [authError, setAuthError] = useState('');

  useEffect(() => {
    if (!GOOGLE_CLIENT_ID) {
      setAuthError('GOOGLE_CLIENT_ID is not configured.');
      return;
    }

    const hashParams = new URLSearchParams(window.location.hash.slice(1));
    const tokenFromHash = hashParams.get('access_token');
    const idTokenFromHash = hashParams.get('id_token');
    const errorFromHash = hashParams.get('error');

    if (errorFromHash) {
      setAuthError(errorFromHash);
      window.history.replaceState(null, '', window.location.pathname + window.location.search);
      return;
    }

    if (tokenFromHash && idTokenFromHash) {
      setAuthError('');
      setAccessToken(tokenFromHash);
      setIdToken(idTokenFromHash);
      setUser(decodeJwtPayload(idTokenFromHash));
      window.history.replaceState(null, '', window.location.pathname + window.location.search);
    }
  }, []);

  const signIn = useCallback(() => {
    if (!GOOGLE_CLIENT_ID) return;

    const params = new URLSearchParams({
      client_id: GOOGLE_CLIENT_ID,
      redirect_uri: `${window.location.origin}/`,
      response_type: 'token id_token',
      scope: `openid email profile ${DRIVE_READONLY_SCOPE}`,
      include_granted_scopes: 'true',
      prompt: accessToken && idToken ? '' : 'consent',
      nonce: createNonce(),
      hd: 'baby-helmet.com',
    });

    window.location.assign(`https://accounts.google.com/o/oauth2/v2/auth?${params}`);
  }, [accessToken, idToken]);

  const signOut = useCallback(() => {
    setAccessToken('');
    setIdToken('');
    setUser(null);
  }, []);

  return {
    idToken,
    accessToken,
    user,
    authReady,
    authError,
    signIn,
    signOut,
  };
}