Synergising Mobile Security

Synergising Mobile Security

In the bustling kitchen of software engineering, product and development teams are like chefs and sous-chefs, each feeding into the other’s culinary creations. Today, we’re cooking up a storm in mobile authentication, exploring how thick mobile applications communicate securely with backend APIs. Grab your aprons—let’s dive into the recipe!

The Appetiser: authenticating the user. A simple and secure approach here is OpenID and OAuth, leveraging trusted service providers like Google Auth. In a Flutter mobile app, integrating Firebase Authentication with Google Sign-In is as smooth as butter on toast.

Here’s how you whip it up in dart:

// Import the necessary packages
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';

Future<UserCredential> signInWithGoogle() async {
  // Trigger the Google Sign-In flow
  final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();

  // Obtain the auth details from the request
  final GoogleSignInAuthentication googleAuth = await googleUser!.authentication;

  // Create a new credential
  final credential = GoogleAuthProvider.credential(
    accessToken: googleAuth.accessToken,
    idToken: googleAuth.idToken,
  );

  // Sign in to Firebase with the Google user credentials
  return await FirebaseAuth.instance.signInWithCredential(credential);
}        

Once authenticated, you have access to the user’s context—like their email—based on the privileges granted in Firebase. It’s like getting the secret family recipe!

The Main Course: Now, onto the backend (BE) API. We need to ensure that our server trusts the user’s identity without making them log in again. Enter the bearer token, specifically the idToken we obtained earlier.

In our Python backend using Firebase Admin SDK, we can verify this token:

from firebase_admin import auth

def verify_id_token(id_token):
    try:
        # Verify the token and decode it
        decoded_token = auth.verify_id_token(id_token)
        uid = decoded_token['uid']
        # Token is valid and not expired
        return uid
    except auth.ExpiredIdTokenError:
        # Token has expired
        return None
    except auth.InvalidIdTokenError:
        # Token is invalid
        return None        

This method ensures secure communication between the mobile app and the backend, all without any secret sauces—no additional auth keys or embedded secrets in the app. It’s the equivalent of a secure kitchen pass-through window; orders (API calls) go in, meals (data) come out, and only authorized staff have access.

The Dessert Dilemma: But wait—what happens when the app needs to make API calls while in the background? Think of periodic activities like refreshing data or syncing, orchestrated by WorkManager or AlarmManager. Since the user isn’t actively engaging with the app, re-authentication isn’t straightforward. Our bearer token might have expired, leaving our background tasks out in the cold.

Here’s the clever bit: we can cache the idToken, which is typically valid for an hour. On the backend, we adjust our token verification to allow a grace period while still ensuring the token’s integrity by verifying its JWT signature.

An idToken is a JSON Web Token (JWT), which consists of three parts:

1. Header: Contains metadata about the token, such as the signing algorithm and type.

2. Payload: Contains the claims or user data (e.g., uid, email).

3. Signature: A cryptographic signature created using the header and payload, signed with Google’s private key.

Even if the token is expired, the signature remains valid for verifying the token’s integrity and authenticity. By verifying the signature against Google’s public keys, we can confirm that the token was indeed issued by Google and hasn’t been tampered with.

Here’s how we modify our verification function to include signature verification and a grace period:

from firebase_admin import auth
from datetime import datetime, timedelta
import jwt
import requests

def verify_id_token_with_grace_period(id_token):
    try:
        # Attempt to verify the token normally
        decoded_token = auth.verify_id_token(id_token)
        return decoded_token['uid']
    except auth.ExpiredIdTokenError:
        # Token has expired; proceed to verify signature manually
        # Fetch Google's public keys
        response = requests.get('https://www.googleapis.com/robot/v1/metadata/x509/[email protected]')
        public_keys = response.json()
        
        # Get the key ID from the token header
        unverified_header = jwt.get_unverified_header(id_token)
        key_id = unverified_header['kid']
        public_key_pem = public_keys.get(key_id)

        if public_key_pem:
            # Decode the token without verifying expiration
            decoded_token = jwt.decode(
                id_token,
                public_key_pem,
                algorithms=['RS256'],
                audience='YOUR_FIREBASE_PROJECT_ID',
                options={'verify_exp': False}
            )
            # Manually check the expiration time
            exp = decoded_token.get('exp')
            expired_at = datetime.utcfromtimestamp(exp)
            if datetime.utcnow() - expired_at < timedelta(days=7):
                # Token expired within the acceptable grace period
                return decoded_token['uid']
            else:
                # Token expired too long ago
                return None
        else:
            # Public key not found; token is invalid
            return None
    except Exception as e:
        # Other errors
        return None        

Verifying the JWT signature is crucial because:

? Authenticity: Confirms the token was issued by a trusted authority (Google).

? Integrity: Ensures the token hasn’t been tampered with.

? User Identity: Validates the claims inside the token, like the user’s UID.

Even if the token has expired, the signature verification guarantees that the token is legitimate. This allows us to trust the user’s identity during the grace period without compromising security.

The Chef’s Special: Now, here’s where the magic happens. This technical workaround requires a keen eye on security posture and risk mitigation. But to truly optimize, the development team needs to feed back into the product strategy.

If a user hasn’t opened the app in two weeks, perhaps we need to spice things up. Maybe it’s time for a push notification with a tempting offer or new feature announcement—something to entice the user back into the app, refreshing their token in the process.

By aligning development constraints with product incentives, we avoid implementing insecure shortcuts or adding unnecessary complexity. Instead, we create a harmonious cycle where user engagement naturally keeps the system secure and functional.

In the end, secure mobile authentication isn’t just about implementing the right protocols—it’s about the symbiotic relationship between product vision and technical execution. By understanding both the kitchen and the dining room, we serve up a dish that’s not only secure and efficient but also delightful for the user.

Bon appétit!

Anshul Khare

Tech Strategist | Engineering Leader | Startup Advisor | IIT Bombay

3 个月

Abhisek Datta You may find this interesting.

Anshul Khare

Tech Strategist | Engineering Leader | Startup Advisor | IIT Bombay

3 个月

Incentivizing product to solve dev/security constraints! Never thought of it this way.

回复
Manjunath Mahashetti

Digital Identity & adv. Cryptography - PHE & FHE(MS SEAL), AGI - RAG, Vector Database, Knowledge Graph, Langchain, Langgraph and Agent Frameworks, Advanced Python, OpenCV, Spring-Boot Microservices Enterprise Application

3 个月

Very helpful and interesting!

要查看或添加评论,请登录

Srinath Venkataramani的更多文章

  • Blind Cosmic Chef

    Blind Cosmic Chef

    Imagine you’re an alien chef, whipping up a cosmic soufflé called “the universe.” You tweak the recipe—say, a pinch of…

    1 条评论
  • Problem to Solution

    Problem to Solution

    Picture this: I’m slouched in a hospital chair, feeling woozy. Suddenly, I notice a shiny new queue system.

    4 条评论
  • Mastering LLM context

    Mastering LLM context

    You know that brilliant colleague who can solve complex problems effortlessly but constantly forgets where they left…

    4 条评论
  • Mastery ballet

    Mastery ballet

    When was the last time you achieved something remarkable? Was it due to your competence—the ability to get things done…

  • The identity game

    The identity game

    Welcome to the circus of the digital age, where identities are the new currency, and everyone’s wearing a mask—except…

  • Viral Vote Wave

    Viral Vote Wave

    Imagine a universe where a 20-minute odd video wields the power to nudge the mighty wheels of democracy. In this world,…

  • Simulated Solitude

    Simulated Solitude

    In the beginning, there was nothing. Which is a bit problematic if you're trying to argue for solipsism because…

  • Design, Intelligence, Deception

    Design, Intelligence, Deception

    In our quest to understand the world, we often encounter a complex interplay of design and natural occurrence. At the…

    2 条评论
  • Context is Everything!

    Context is Everything!

    Imagine you’re at a family dinner, and aunt May remarks about the 'elephant in the room.' While you're looking around…

  • Feedback Loops: The Universal Constructors

    Feedback Loops: The Universal Constructors

    This article is presented in a conversational style between me and a generative AI model. It explores the omnipresence…

    4 条评论

社区洞察

其他会员也浏览了