Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add state params in Google oauth #192

Merged
merged 1 commit into from
Sep 30, 2024

Conversation

julianfox
Copy link
Contributor

This update add the state parameter to the Google OAuth flow to enhance security and help maintain state between the request and callback.

For more details: Google OAuth 2.0 - Request Parameter: state.

@atinux atinux changed the title Add state params in Google oauth chore: add state params in Google oauth Sep 30, 2024
@atinux atinux merged commit f75e680 into atinux:main Sep 30, 2024
3 checks passed
@yandiro
Copy link

yandiro commented Dec 15, 2024

Thanks @julianfox and @atinux!

How do I use this?

@julianfox
Copy link
Contributor Author

julianfox commented Dec 16, 2024

Hi @yandiro,
You can include a state string as a query parameter in your Google Auth request. Here's an example:

const stateString = btoa(unescape(encodeURIComponent(JSON.stringify(state))));
const authUrl = `/auth/google?state=${stateString}`;

The state string will then be included in the signup success response, and you can retrieve it as follows:

export default defineOAuthGoogleEventHandler({
  config: {
    scope: ['email', 'profile'],
  },
  async onSuccess(event: any, { user, tokens }: { user: any, tokens: any }) {
    const query = getQuery<{ code?: string, state?: string }>(event);

    const state = query.state 
      ? JSON.parse(decodeURIComponent(escape(atob(query.state)))) 
      : {};

    // Your signup logic here
  },
});

@adnanerlansyah403
Copy link

Hi @yandiro, You can include a state string as a query parameter in your Google Auth request. Here's an example:

const stateString = btoa(unescape(encodeURIComponent(JSON.stringify(state))));
const authUrl = `/auth/google?state=${stateString}`;

The state string will then be included in the signup success response, and you can retrieve it as follows:

export default defineOAuthGoogleEventHandler({
  config: {
    scope: ['email', 'profile'],
  },
  async onSuccess(event: any, { user, tokens }: { user: any, tokens: any }) {
    const query = getQuery<{ code?: string, state?: string }>(event);

    const state = query.state 
      ? JSON.parse(decodeURIComponent(escape(atob(query.state)))) 
      : {};

    // Your signup logic here
  },
});

How about this example sir? is it a good way to send the state?

// auth/login.vue
const openAuthPopup = (provider) => {
  const state = generateRandomString();
  // URL dinamis berdasarkan provider
  const authUrls = {
    google: `/api/auth/google?state=${state}`,
    github: `/api/auth/github?state=${state}`,
    facebook: `/api/auth/facebook?state=${state}`,
  };

  const authUrl = authUrls[provider];

  // Jika provider tidak ditemukan, tampilkan pesan error
  if (!authUrl) {
    console.error(`Provider ${provider} tidak didukung.`);
    alert(`Provider ${provider} tidak didukung.`);
    return;
  }

  // Ukuran dan posisi popup
  const width = 500;
  const height = 600;
  const left = (window.innerWidth - width) / 2;
  const top = (window.innerHeight - height) / 2;

  // Buka popup
  const popup = window.open(
    authUrl,
    `${provider}Login`,
    `width=${width},height=${height},top=${top},left=${left},scrollbars=yes,resizable=yes`
  );

  // Periksa jika popup diblokir
  if (!popup || popup.closed || typeof popup.closed === 'undefined') {
    alert('Popup blocked! Please allow popups for this site.');
  }
};

const handleOAuthMessage = (event) => {
  if (event.origin !== window.location.origin) return; // Validate the origin

  const { success, user, tokens, query, error } = event.data;
  console.log(tokens, query)

  if (success) {
      const { account, sessionTokens } = storeToRefs(authStore());
      account.value = user;
      sessionTokens.value = tokens;
    // Handle successful login, e.g., update the state or redirect
    navigateTo('/auth/register')
  } else {
    console.error('OAuth login failed:', error);
    // Handle login error, e.g., show a notification
  }
};

// method generateRandomString

// utils/random.js

/**
 * Generates a cryptographically secure random string
 * @param {number} length - The length of the random string in bytes (default: 32)
 * @returns {string} - A hexadecimal random string
 */
export const generateRandomString = (length = 32) => {
    const array = new Uint8Array(length);
    window.crypto.getRandomValues(array); // Secure random values
    return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
};

@julianfox
Copy link
Contributor Author

I implemented it only for the Google provider, not sure if it's doable for Github or Facebook.

@adnanerlansyah403
Copy link

adnanerlansyah403 commented Jan 17, 2025

I implemented it only for the Google provider, not sure if it's doable for Github or Facebook.

Oh, okay sir, thank you for your information. But can I ask a question again? Does the code from the result of the getQuery
method expire immediately after a successful login with Google? Because when I used it and sent it to the backend, it gave me this message: 'failed to exchange Google token.

https://accounts.google.com/o/oauth2/v2/auth?client_id=YOUR_CLIENT_ID&redirect_uri=http://localhost:3000/api/auth/oauth/google/callback&response_type=code&scope=email profile openid&access_type=offline&state=5a678eaddb3212f627ca968d8d5b3bd82d4a2acb

btw, I followed this tutorial for the login flow guide with google.
https://medium.com/@tony.infisical/guide-to-using-oauth-2-0-to-access-google-apis-dead94d6866d

@adnanerlansyah403
Copy link

adnanerlansyah403 commented Jan 17, 2025

I implemented it only for the Google provider, not sure if it's doable for Github or Facebook.

I'm very stressful with this issue sir, please let me know if you know something about this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants