POST/api/auth/google

Google OAuth Login

Authenticate or register a user using Google OAuth. If the user doesn't exist, a new account is automatically created.

Request

Body Parameters

ParameterTypeRequiredDescription
idTokenstringYesGoogle ID token from Google Sign-In

Example Request

curl -X POST https://api.storno.ro/api/auth/google \
  -H "Content-Type: application/json" \
  -d '{
    "idToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjE5ZmUyYTdiNjc5NTIzOTYwNmNhMGE3NTA3N..."
  }'

Response

Success Response (200 OK)

{
  "token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "def50200a1b2c3d4e5f6...",
  "isNewUser": false
}
FieldTypeDescription
tokenstringJWT access token, valid for 1 hour
refresh_tokenstringRefresh token used to obtain new access tokens
isNewUserbooleantrue if account was just created, false for existing user

Error Codes

CodeDescription
400Bad Request - Missing or invalid ID token
401Unauthorized - Invalid Google ID token or token verification failed
403Forbidden - Google account email not verified
429Too Many Requests - Rate limit exceeded

Error Response Examples

Invalid ID Token (401)

{
  "code": 401,
  "message": "Invalid Google ID token."
}

Email Not Verified (403)

{
  "code": 403,
  "message": "Google account email must be verified."
}

Automatic Account Creation

When a user signs in with Google for the first time:

  1. Email Verification: The system verifies the Google ID token with Google's servers
  2. User Lookup: Checks if a user with the Google email already exists
  3. Auto-Registration: If not found, creates a new user account with:
    • Email from Google account
    • First and last name from Google profile
    • Email marked as confirmed (no confirmation email needed)
    • Default organization created with owner role
  4. Token Issuance: Returns JWT tokens for immediate authenticated access

Integration with Google Sign-In

Frontend Setup (HTML/JavaScript)

<!-- Load Google Sign-In library -->
<script src="https://accounts.google.com/gsi/client" async defer></script>

<script>
  function handleCredentialResponse(response) {
    // Send ID token to your backend
    fetch('https://api.storno.ro/api/auth/google', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ idToken: response.credential }),
    })
      .then(res => res.json())
      .then(data => {
        // Store tokens
        localStorage.setItem('token', data.token);
        localStorage.setItem('refresh_token', data.refresh_token);

        // Handle new vs returning user
        if (data.isNewUser) {
          console.log('Welcome! Account created successfully.');
          // Redirect to onboarding
          window.location.href = '/onboarding';
        } else {
          console.log('Welcome back!');
          // Redirect to dashboard
          window.location.href = '/dashboard';
        }
      })
      .catch(error => {
        console.error('Authentication failed:', error);
      });
  }

  // Initialize Google Sign-In
  window.onload = function() {
    google.accounts.id.initialize({
      client_id: 'YOUR_GOOGLE_CLIENT_ID.apps.googleusercontent.com',
      callback: handleCredentialResponse
    });

    google.accounts.id.renderButton(
      document.getElementById('googleSignInButton'),
      { theme: 'outline', size: 'large' }
    );
  };
</script>

<div id="googleSignInButton"></div>

Mobile Setup (React Native)

import { GoogleSignin } from '@react-native-google-signin/google-signin';

// Configure Google Sign-In
GoogleSignin.configure({
  webClientId: 'YOUR_GOOGLE_CLIENT_ID.apps.googleusercontent.com',
});

// Sign in function
async function signInWithGoogle() {
  try {
    await GoogleSignin.hasPlayServices();
    const userInfo = await GoogleSignin.signIn();
    const idToken = userInfo.idToken;

    const response = await fetch('https://api.storno.ro/api/auth/google', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ idToken }),
    });

    const data = await response.json();
    // Store tokens and navigate
  } catch (error) {
    console.error('Google Sign-In failed:', error);
  }
}

MFA Challenge Response (200 OK)

If the user has two-factor authentication enabled, the endpoint returns an MFA challenge instead of tokens:

{
  "mfa_required": true,
  "mfa_token": "a1b2c3d4e5f6789...",
  "mfa_methods": ["totp", "backup_code"]
}

Complete the challenge by calling Verify MFA Challenge with the mfa_token and a valid code.

Usage Notes

  • Google ID tokens are verified server-side for security
  • When the user has MFA enabled, handle the mfa_required response by redirecting to MFA verification
  • Token verification includes checking signature, expiration, and audience
  • Users can link multiple authentication methods (password + Google) to the same email
  • Google OAuth does not require a separate password
  • Email confirmation is not required for Google OAuth users
  • Rate limiting: maximum 10 OAuth attempts per minute per IP address

Security Considerations

  • Always validate ID tokens on the server side
  • Never trust client-side token validation alone
  • ID tokens expire quickly (typically 1 hour)
  • Store Google ID tokens securely and never expose them in URLs
  • Use HTTPS for all authentication requests