Hotwire Native Weekly

Hotwire Native Weekly

Hotwire Native deep dive: Authentication

How to handle authentication across web, iOS, and Android. All without writing tons of native code or adding new API endpoints.

Joe Masilotti's avatar
Joe Masilotti
Oct 23, 2025
∙ Paid
10
9
Share

Hotwire Native brings your mobile-web friendly Rails app to iOS and Android with just a few lines of code. And without any additional configuration (or even native code!) you get a lot for free.

But one thing that isn’t handled by default, or even mentioned in the documentation, is authentication. And because of that, I often see developers over-engineer it in their Hotwire Native apps.

Here’s the thing: authentication doesn’t have to be complicated. In fact, by taking advantage of a shared cookie we can simplify the sign in flow for web, iOS, and Android. And keep all of our logic in the Rails codebase.

Here’s my authentication approach for an app experience that requires the user to sign in. When the app launches for the first time you see the Sign In screen. Then, after you sign in, you’re presented with a native tab bar.

I often implement something exactly like this for my clients:

  1. Use a long-lived cookie to authenticate across all platforms:

cookies.signed.permanent[:session_id] = session.id
  1. Render a <meta> tag on every page with the user’s authentication status:

<meta data-controller="bridge--authentication"
  data-bridge-authenticated="<%= authenticated? %>">
  1. Wire that up to a bridge component:

class AuthenticationComponent: BridgeComponent {
    override class var name { "authentication" }

    override func onReceive(message: Message) {
        if message.event == "signIn" {
            signIn()
        } else if message.event == "signOut" {
            signOut()
        }
    }
}
  1. And toggle the tab bar when the user signs in or out:

func signIn() {
    tabBarController.tabBar.isHidden = true
    tabBarController.load(tabs)
}

func signOut() {
    tabBarController.tabBar.isHidden = false
    tabBarController.load([newSessionTab])
}

Read on for the exact approach I take, including all the gotchas and pitfalls. Also, a zip file with the full source code for the Rails, iOS, and Android apps.

Keep reading with a 7-day free trial

Subscribe to Hotwire Native Weekly to keep reading this post and get 7 days of free access to the full post archives.

Already a paid subscriber? Sign in
© 2025 Joe Masilotti
Privacy ∙ Terms ∙ Collection notice
Start your SubstackGet the app
Substack is the home for great culture