Webview Authentication

MentraOS provides a simple and secure way for apps to identify users within webviews. When a user opens your web application through the MentraOS Mobile App, you can automatically identify them without requiring a separate login process. Auth middleware is applied automatically by MiniAppServer. You don’t need to set it up - just call getMentraAuth(c) on any route.
import { MiniAppServer, getMentraAuth } from "@mentra/sdk";

const app = new MiniAppServer({
  packageName: "org.example.myapp",
  apiKey: process.env.API_KEY!,
  port: 3000,
});

app.get("/webview", (c) => {
  const auth = getMentraAuth(c);
  const userId = auth.userId;

  if (userId) {
    return c.html(`Welcome user ${userId}!`);
  } else {
    return c.html('Please open this page from the MentraOS app, or <a href="/mentra-auth">login with Mentra</a>');
  }
});

await app.start();

What Is Webview Authentication?

Webview authentication lets your web application identify MentraOS users without requiring them to log in separately.

When a user opens your webview through the MentraOS Mobile App:

  1. The MentraOS app automatically appends a temporary authentication token to your URL
  2. The SDK’s built-in auth middleware automatically exchanges this token for the user’s ID and sets a signed cookie
  3. Your webview can then provide a personalized experience based on the user’s identity

When a user opens your website in a regular browser (not the MentraOS app):

Want to let users access your app from a regular browser? Have them visit:https://account.mentra.glass/auth?packagename=your.package.nameThey’ll sign in with their Mentra account and be redirected to your app automatically.
Here’s what happens under the hood:
  1. Your app detects the user isn’t authenticated (no userId from getMentraAuth(c))
  2. You redirect them to /mentra-auth, which the SDK handles automatically
  3. The user is sent to account.mentra.glass/auth?packagename=your.package.name where they sign in with their Mentra account (email, Google, or Apple) and authorize your app
  4. After the user clicks “Allow”, they are redirected back to your app’s webview URL with a signed token in the query parameters
  5. The auth middleware automatically validates this token and sets a signed cookie for future requests

How It Works

1. Include a Webview in Your App

Specify a webview URL in your app’s configuration through the MentraOS Developer Console:
  1. Log in to the MentraOS Developer Console
  2. Navigate to your app’s settings
  3. Add your Webview URL
  4. Save your changes

2. Authentication Is Automatic

MiniAppServer applies auth middleware to all routes automatically. You don’t need to call createAuthMiddleware or configure a cookieSecret - the SDK uses your apiKey to sign session cookies by default.
import { MiniAppServer, getMentraAuth } from "@mentra/sdk";

const app = new MiniAppServer({
  packageName: "org.example.myapp",
  apiKey: process.env.API_KEY!,
  port: 3000,
});

// Auth is already set up. Just use getMentraAuth(c) on any route.

3. Access User Identity in Your Routes

Call getMentraAuth(c) on any route to get the user’s identity. The auth context is available everywhere - no middleware application needed per-route.
app.get("/webview", (c) => {
  const auth = getMentraAuth(c);
  const userId = auth.userId;

  if (userId) {
    return c.html(`<h1>Welcome, ${userId}!</h1>`);
  } else {
    return c.html('<p>Please <a href="/mentra-auth">sign in with Mentra</a></p>');
  }
});

app.get("/api/me", (c) => {
  const auth = getMentraAuth(c);
  return c.json({ userId: auth.userId });
});

app.get("/api/settings", (c) => {
  const auth = getMentraAuth(c);
  const userId = auth.userId;
  // Load user-specific settings...
  return c.json({ userId, settings: {} });
});
If the user isn’t authenticated, auth.userId is null. It’s your route handler’s job to check and return a 401 or redirect if needed.

4. Handle Unauthenticated Users with the OAuth Flow

If the user opens your webview in a regular browser (not through the MentraOS app), they won’t have a token automatically. The SDK provides a built-in /mentra-auth route that redirects users to the Mentra OAuth consent screen. Add a “Sign in with Mentra” button to your unauthenticated view:
<a href="/mentra-auth">
  <img src="https://account.mentra.glass/sign-in-mentra.png" alt="Sign in with Mentra" width="140" height="50" />
</a>
Sign in with Mentra When a user clicks “Sign in with Mentra”, they are redirected to:
https://account.mentra.glass/auth?packagename=your.package.name
This is the Mentra OAuth consent screen. Here’s what happens:
  1. Sign in: If the user isn’t already signed in to their Mentra account, they are prompted to sign in (email, Google, or Apple).
  2. Consent: The user sees your app’s name, icon, and description, and is asked to authorize the app to access their basic profile.
  3. Redirect: After the user clicks “Allow”, they are redirected back to your app’s Webview URL (configured in the Developer Console) with a signed token appended:
    https://your-app.com/webview?aos_signed_user_token=eyJ...&source=oauth
    
  4. Token validation: The auth middleware automatically validates the token and sets a signed cookie for future requests.
The token issued during the OAuth flow expires after 10 minutes. After that, the user will need to re-authenticate. The SDK handles this automatically when the user returns through the MentraOS app.

Complete Example

import { MiniAppServer, getMentraAuth, type MentraSession } from "@mentra/sdk";

const app = new MiniAppServer({
  packageName: "org.example.myapp",
  apiKey: process.env.API_KEY!,
  port: 3000,
});

// Public health check
app.get("/api/health", (c) => c.json({ ok: true }));

// Auth is automatic - getMentraAuth(c) works on every route
app.get("/api/user/me", (c) => {
  const auth = getMentraAuth(c);
  if (!auth.userId) return c.json({ error: "Not authenticated" }, 401);
  return c.json({ userId: auth.userId });
});

// Webview route
app.get("/webview", (c) => {
  const auth = getMentraAuth(c);

  if (auth.userId) {
    return c.html(`
      <h1>Hello, ${auth.userId}</h1>
      <p>You are authenticated.</p>
    `);
  }

  return c.html(`
    <h1>Welcome</h1>
    <p>Please sign in to continue.</p>
    <a href="/mentra-auth">
      <img src="https://account.mentra.glass/sign-in-mentra.png" alt="Sign in with Mentra" />
    </a>
  `);
});

// Session handler
app.onSession((session: MentraSession) => {
  session.display.showTextWall("App connected");
});

await app.start();

Common Use Cases

Webview authentication enables:
  • Personalized dashboards and content
  • User-specific settings and preferences
  • Integration with your existing user database
  • Seamless experiences without additional login steps

Migrating from v2

In v2, authentication used Express middleware with req.authUserId:
// v2 (Express)
const expressApp = server.getExpressApp();
expressApp.get("/webview", (req: AuthenticatedRequest, res) => {
  const userId = req.authUserId;
  res.send(`Welcome ${userId}`);
});

// v3 (Hono) - auth is automatic
app.get("/webview", (c) => {
  const auth = getMentraAuth(c);
  return c.html(`Welcome ${auth.userId}`);
});
Key differences:
  • getExpressApp() is removed. Routes are added directly on the MiniAppServer instance.
  • AuthenticatedRequest and req.authUserId are replaced by getMentraAuth(c).userId.
  • No createAuthMiddleware() call needed. Auth middleware is applied automatically by MiniAppServer.
  • No cookieSecret needed. The SDK uses your apiKey to sign cookies by default.
See the Migration Guide for the full list of changes.

React Webviews

If you want to build your frontend webview using React, see the React Webviews guide. The @mentra/react package handles authentication on the frontend - it works the same regardless of whether your backend uses v2 or v3.