as

Settings
Sign out
Notifications
Alexa
Amazon Appstore
Ring
AWS
Documentation
Support
Contact Us
My Cases
Get Started
Design and Develop
Publish
Reference
Support

Account Login Integration Guide

The Vega Media Account Login API provides a way for apps to report their authentication status to the system.

Refresh the user's login status upon each launch, which is done by the Account Login API. There are two Account Login states: signed in, and signed out. By keeping the login status up-to-date, apps make sure that users can access appropriate content and features. The interface enables apps to communicate a boolean value indicating whether a user logged in, both at launch and whenever the login state changes. The system can also query this status as needed, enabling a personalized user experience.

Products can leverage this information to feature or filter content from user authenticated services, giving instant access to content.

The Account Login functionality offers two key components for managing authentication status: the updateStatus method, and the handleReadStatus callback function. The updateStatus method reports an app's current login status for real-time updates when the authentication state changes. The handleReadStatus callback function can respond to system queries about the app's current login status. Both methods use the StatusType for account status, with two possible values: SIGNED_IN and SIGNED_OUT.

Vega Media Account Login API reference

For reference documentation about this API, see Account Login API.

Vega Media Account Login common use cases

Apps should update the system with their login status in the following situations:

  • When the app initially launches.
  • When there's a change in the user's subscription status.
  • When requested from other services.

Install and set up Vega Media Account Login

Step 1: Update the app manifest

Use the service component to handle a portion of the Account Login interactions. Familiarize yourself with service components, also called headless components. Get a service running alongside your interactive component to make this integration easier to perform and troubleshoot. See the service component documentation.

First, update your app manifest to use the Vega Media Account Login API. When modifying the manifest entries, replace com.amazondeveloper.media.sample with your app's package ID, as seen in the following example. Developers most often implement the Account Login API as a service, to provide the account login status, especially during read operations. Don't require users to open an interactive interface-based app. Developers usually implement media provider apps as interactive apps to handle the user interface. Your interactive and service apps should exchange Account Login information. You can exchange Account Login information by using shared files or other inter-process communication mechanisms.

The following example shows a sample manifest for both the Content Launcher and Account Login APIs. It defines both interactive and service components.

Copied to clipboard.

schema-version = 1

[package]
title = "<Your app title>"
id = "com.amazondeveloper.media.sample"

[components]

[[components.interactive]]
id = "com.amazondeveloper.media.sample.main"
runtime-module = "/com.amazon.kepler.keplerscript.runtime.loader_2@IKeplerScript_2_0"
launch-type = "singleton"
# The category "com.amazon.category.kepler.media" is only necessary for the primary component. You can find "com.amazon.category.kepler.media" 
# in the [[extras]] section of the manifest using the "component-id" value.
categories = ["com.amazon.category.main", "com.amazon.category.kepler.media"]

[[components.service]]
id = "com.amazondeveloper.media.sample.interface.provider"
runtime-module = "/com.amazon.kepler.headless.runtime.loader_2@IKeplerScript_2_0"
launch-type = "singleton"

[processes]

[[processes.group]]
component-ids = ["com.amazondeveloper.media.sample.main"]

[[processes.group]]
component-ids = ["com.amazondeveloper.media.sample.interface.provider"]

[offers]

[[offers.interaction]]
id = "com.amazondeveloper.media.sample.main"

[[offers.service]]
id = "com.amazondeveloper.media.sample.interface.provider"
required-privileges = ["com.amazon.multimedia.privilege.session.manage"]

[[message]]
uri = "pkg://com.amazondeveloper.media.sample.main"
# Match the privileges used in [[offers.interaction]]. If you do not have privileges, use `*`.
sender-privileges = ["*"]
receiver-privileges = ["self"]

[[offers.module]]
id = "/com.amazondeveloper.media.sample.module@ISomeUri1"
includes-messages = ["pkg://com.amazondeveloper.media.sample.main"]

[[extras]]
key = "interface.provider"
component-id = "com.amazondeveloper.media.sample.main"

[extras.value.application]
[[extras.value.application.interface]]
interface_name = "com.amazon.kepler.media.IContentLauncherServer"
attribute_options = ["partner-id"]
static-values = { "partner-id" = "<Your partner id>" }

[[extras.value.application.interface]]
interface_name = "com.amazon.kepler.media.IAccountLoginServer"
attribute_options = ["Status"]
# In this manifest example, Amazon defines both the Content Launcher and the Account Login interface.
# Since the service component should handle the Account Login cluster instead of an
# interactive one for responsiveness, "override_attribute_component" redirects
# calls for the "Status" attribute to the service component.
override_attribute_component = { Status = "com.amazondeveloper.media.sample.interface.provider" }

[needs]

[[needs.module]]
# The dot (.) after "media" is intentional in this format. This notation will change in a 
# future release.
id = "/com.amazon.kepler.media.@IAccountLogin1"

[[needs.module]]
id = "/com.amazon.kepler.media@IContentLauncher1"

Media apps often require integration with three key APIs:

  • Content Launcher Cluster API for finding and launching content
  • Vega Media Controls API for controlling launched media
  • Account Login API for communicating Account Login status to the system

Developers most often implement the Content Launcher and Vega Media Control APIs as interactive components to handle Vega media queries. This component is specified in the app manifest's extras section using the interface.provider key, as shown in the following TOML snippet and in the previous example.

Copied to clipboard.

[[extras]]
key = "interface.provider"
component-id = "<primary interactive component-id>"

The Account Login API functions as a service app, enabling the system to query Account Login status without waking up the entire app. The Account Login API uses a single "Status" attribute, which the service component handles. For proper routing of login status attribute interactions, the app manifest must specify the service component using the 'override_attribute_component' setting. The following TOML is an example of how to use the 'override_attribute_component':

Copied to clipboard.

override_attribute_component = { Status = "<service component-id implementing Account Login api>" }

Use this approach to optimize system performance and provide a clear separation between media control and account management functionalities.

Step 2: Include package dependencies

The Vega Media Account Login API is offered to TypeScript developers using the system turbo module amzn/kepler-media-account-login. This turbo module is part of the SDK package. To use the API, update the package.json file to take the turbo module as a dependency, and add amzn/headless-task-manager to create a headless service app.

Copied to clipboard.

"dependencies": {
  "@amazon-devices/kepler-media-account-login": "^1.1.0",
  "@amazon-devices/headless-task-manager": "^1.1.0"
}

Step 3: Add the Vega Media Account Login business logic

Create a file named AccountLoginWrapper.ts to contain the core business logic for the Vega Media Account Login API. In this file, create and export a class named AccountLoginWrapper. This class has a single member variable: an instance of the IAccountLoginServerAsync interface, used to interact with the Account Login server. This file also globally creates an instance of AccountLoginServerComponent and store it in a variable named accountLoginServerComponent.

Copied to clipboard.

import { IComponentInstance } from '@amazon-devices/react-native-kepler';
import {
  AccountLoginServerComponent,
  IAccountLoginHandlerAsync,
  StatusType,
  IAccountLoginServerAsync,
  IStatus,
} from '@amazon-devices/kepler-media-account-login';
import AsyncStorage from '@react-native-async-storage/async-storage';

const accountLoginServerComponent = new AccountLoginServerComponent();

export class AccountLoginWrapper {
  accountLoginServer?: IAccountLoginServerAsync;
}

Step 4: Asynchronously return the Account Login status

Now using the IAccountLoginHandlerAsync interface, implement the handleReadStatus() method that takes no arguments and returns a Promise<IStatus>. By designing the method in this way, the service app asynchronously returns the Account Login status without blocking the caller. The Promise<IStatus> return type indicates that the method eventually resolves with an IStatus object, which likely contains information about the current login state.

The headless service created later in Step 8 invokes the handleReadStatus() handler. Since the interactive component (UI app) and the headless service run in separate processes, they do not share in-memory state. Relying on in-memory variables is insufficient. For reliable communication between the two components, use a shared mechanism for persisting and transferring the login status. Read the login status asynchronously from this persistent storage. Currently the headless service supports React's AsyncStorage and the Vega File System. MMKV is not supported. This example uses AsyncStorage.

Here are some examples of component implementations that leverages AsyncStorage.

Copied to clipboard.

// Interactive Component
// Inside "com.amazondeveloper.media.sample.main".
const onLoginChange = async (newStatus: boolean) => {
  await AsyncStorage.setItem('loginStatus', newStatus);
};

Copied to clipboard.

// Service Component
// Inside "com.amazondeveloper.media.sample.interface.provider".
const getLoginStatus = async (): boolean => {
  return await AsyncStorage.getItem('loginStatus');
};

Register the handleReadStatus() handler to return the login status when the system invokes it. getLoginStatus() must read the status through persistent storage as seen previously. getLoginStatus() is app specific.

Copied to clipboard.

export class AccountLoginWrapper {
  async getAccountLoginStatus(): IStatus {
    return accountLoginServerComponent.makeStatusBuilder()
      .status(
        // Fetch status from persistent storage.
        (await getLoginStatus())
          ? StatusType.SIGNED_IN
          : StatusType.SIGNED_OUT)
      .build();
  }

  createAccountLoginHandler(): IAccountLoginHandlerAsync {
    return {
      handleReadStatus: async (): Promise<IStatus> => {
        console.log('handleReadStatus() invoked.')
        return await this.getAccountLoginStatus();
      }
    };
  }
}

Next, introduce the setupAccountLoginServer() method in the AccountLoginWrapper class. This method accepts an IComponentInstance object as a parameter. Implement it in the following manner:

  1. Create a singleton instance of IAccountLoginServerAsync and store it in the member variable accountLoginServer.
  2. Next, invoke setHandlerForComponent(), passing in the handleReadStatus() handler created in Step 4, and ComponentInstance already provided.

Copied to clipboard.

export class AccountLoginWrapper {
  setupAccountLoginServer(componentInstance: IComponentInstance) {
    console.log('setupAccountLoginServer() invoked.');
    try {
      this.accountLoginServer = accountLoginServerComponent.getOrMakeServer();
    } catch (error) {
      this.accountLoginServer = undefined;
      console.error(
        'setupAccountLoginServer() failed creating Account Login server: ',
        error,
      );
      return;
    }

    try {
      this.accountLoginServer?.setHandlerForComponent(this.createAccountLoginHandler(), componentInstance);
    } catch (error) {
      console.error(
        'setupAccountLoginServer() failed to set handler: ',
        error,
      );
    }
    console.log('setupAccountLoginServer() completed.');
  }
}

Step 6: Update the Account Login status

To update the Account Login status, use the updateStatus() method asynchronously. Be sure to store the login status in persistent storage before calling this function.

Copied to clipboard.

export class AccountLoginWrapper {
  async updateStatus(loginStatus: boolean) {
    console.log('updateStatus() invoked.');
    const status = accountLoginServerComponent.makeStatusBuilder()
      .status(loginStatus ? StatusType.SIGNED_IN : StatusType.SIGNED_OUT)
      .build();
    try {
      this.accountLoginServer?.updateStatus(status);
    } catch (error) {
      console.error(
        'updateStatus() Failed updating login status: ',
        error,
      );
    }
  }
}

Step 7: Integrate the Account Login server with the service lifecycle

To make this integration, the AccountLoginWrapper class exposes two methods: onStart() and onStop().

onStart()

The onStart() method initializes the Account Login server by calling setupAccountLoginServer() with the provided IComponentInstance.

onStop()

The onStop() method adds the cleanup logic needed when the service stops.

After implementing these methods, create a singleton instance called AccountLoginWrapperInstance and use it to expose two equivalent top-level methods: onStartService() and onStopService(). Use these methods for both the service and interactive components to start and stop the Account Login server.

Copied to clipboard.

export class AccountLoginWrapper {
  onStart(componentInstance: IComponentInstance): Promise<void> {
    this.setupAccountLoginServer(componentInstance);
    return Promise.resolve();
  }

  onStop(): Promise<void> {
    // Add any cleanup code here.
    return Promise.resolve();
  }
}

export const AccountLoginWrapperInstance = new AccountLoginWrapper();

export const onStartService = (componentInstance: IComponentInstance): Promise<void> => {
  return AccountLoginWrapperInstance.onStart(componentInstance);
};

export const onStopService = (): Promise<void> => {
  return AccountLoginWrapperInstance.onStop();
};

Step 8: Implement a headless service

A headless service is a background process that runs without a user interface, utilizing its own React Native runtime. This service is key for responding to login status requests and is created by the following steps.

  1. Create a new file named service.js in your app's root directory.
  2. Import AccountLoginWrapper, created in the previous steps, and also import headless-task-manager.

    Copied to clipboard.

     import { HeadlessEntryPointRegistry } from '@amazon-devices/headless-task-manager';
     import { onStartService, onStopService } from './src/AccountLoginWrapper';
    
  3. Define the start and stop entry points.

    Copied to clipboard.

     HeadlessEntryPointRegistry.registerHeadlessEntryPoint2(
       'com.amazondeveloper.media.sample.interface.provider::onStartService',
       () => onStartService
     );
    
     HeadlessEntryPointRegistry.registerHeadlessEntryPoint2(
       'com.amazondeveloper.media.sample.interface.provider::onStopService',
       () => onStopService
     );
    
    • Replace com.amazondeveloper.media.sample with your app's actual package ID.
    • The entry point naming convention is: <app_package_id>.interface.provider::onStartService or ::onStopService.

Fire TV system components automatically invoke onStartService() to initialize the Account Login server as a headless service. During this process, the handleReadStatus() function is registered for the specific service component instance.

When the system invokes this handler later, handleReadStatus() returns the current login state (signed-in or signed-out) as reported by the app.

Step 9: Initialize the Account Login server to report the login state

The interactive component (UI app) must also initialize the Account Login server to report the user's login state using the updateStatus() method.

Copied to clipboard.

// Inside "com.amazondeveloper.media.sample.main".
useEffect(() => {
  AccountLoginWrapperInstance.onStart(componentInstance);

  return () => {
    AccountLoginWrapperInstance.onStop();
  };
}, []);

Step 10: Send login status updates

The interactive component (UI app) must call the updateStatus() method with the current login status in the following scenarios:

  1. When the user launches the app.
  2. When the user's login status changes.

Store the status in persistent storage each time before calling updateStatus(), so that handleReadStatus() retrieves and returns the correct value. This way, the system consistently reflects the user's authentication state, providing a seamless user experience.

This setup lets your app to manage login status requests, even when the main app is not actively running.

You have now created a single instance of IAccountLoginServerComponentAsync. The system creates a link between the handleReadStatus() method and the IComponentInstance, so that any read requests are directed to the service component. Doing this handles Account Login status queries. Call the updateStatus() method to force a login status update, or whenever the status changes.

Troubleshooting Vega Media Account Login

There are several possible issues that can arise when integrating with Account Login, but here are some more common ones.

Confirm The service component starts

See if your updateStatus() call is picked up. If it is, the service component will start without crashing.

You can check on your updateStatus() call by capturing logs before running vega device launch-app com.your.app.id.interface.provider, and watch your service component get through its start-up sequence. Check the logs corresponding to your service component name, and see if any crashes occur during this phase. Find the logs after you reach the registerHeadlessEntryPoint() (onStartService) entrypoint.

If you have a failure or crash according to the logs, you may find the Vega Crash Debugging Documentation a useful reference.

Confirm the handler is called

Once you are confident your service is starting successfully, confirm that your service properly registers a handle using setHandlerForComponent(). You can add logs around this invocation to confirm this path is getting hit. You can find equivalent logs from for handle_set_response_handler for your service component ID to confirm.

Add logs around handleReadStatus() to confirm it is functioning as expected.


Last updated: Feb 17, 2026