GDK Glassware の認証

GDK Glassware でウェブサービスに対してユーザーを認証する必要がある場合、GDK には、ユーザーが Glassware をインストールするときに認証情報を入力できるようにする API が用意されています。

この API を使用すると、Glass ユーザーに一貫したユーザー エクスペリエンスを提供でき、独自のカスタム認証スキームを実装するオーバーヘッドを回避できます。

Google API サービス アカウントを作成する

認証が正しく設定されると、ウェブアプリのバックエンドは Mirror API を使用して、ユーザーがサービスで認証された後、ユーザーのアカウント情報を Glass にプッシュします。

この API にアクセスするには、Google API プロジェクトを作成し、「サービス アカウント」(「ウェブ アプリケーション」以外)のクライアント ID を作成します。サービス アカウントを使用すれば、認証情報を Glass にプッシュする権限をアプリに付与する必要がなくなります。また、OAuth 権限ページと独自の認証ページの両方が表示されることもなくなります。

このアカウントを作成するには:

  1. Google Developers Console にアクセスします。
  2. [プロジェクトを作成] ボタンをクリックし、必要な情報を入力します。
  3. プロジェクトが作成されたら、プロジェクト番号をメモします。これは後で必要になります。
  4. [API と認証] で [API] をクリックし、新しいプロジェクトで Google Mirror API を有効にします。
  5. [API と認証] で [認証情報]、[新しいクライアント ID を作成] の順にクリックします。[サービス アカウント] チェックボックスをオンにして、プロジェクトの新しい OAuth 2.0 クライアント ID を作成します。
  6. ポップアップ ウィンドウに、秘密鍵がパソコンにダウンロードされていることが通知され、その秘密鍵のパスワードが表示されます。このウィンドウを閉じると、この秘密鍵をダウンロードしたり、パスワードを再び表示したりすることはできなくなります。紛失した場合は、新たに作成する必要があります。
  7. サービス アカウントのメールアドレスをメモしておきます。このメールアドレスは、後で API 呼び出しを行う際に必要になります。

Glassware に関するメタデータの提供

Glassware を送信する準備ができたら、以下の情報を提供する必要があります。これにより、実装時に Glassware が正しく認証されるように設定できます。

  • 認証 URL。ユーザーが MyGlass で Glassware をオンにすると、この URL にリダイレクトされます。
  • アカウントの種類(Glass デバイスで Android AccountManager API を呼び出すときに使用する文字列)
  • AndroidManifest.xml のアプリのパッケージ名
  • 上記で作成したプロジェクトの数値の Google API プロジェクト ID
  • MyGlass にアップロードする APK。テストでは、MyGlass から Glassware がオンになったときの最初のダウンロードを処理するために、この APK を 1 回だけ指定する必要があります。その後は、デバイス上の APK を上書きして、ローカルで反復処理とデバッグを行うことができます。この APK は次の条件を満たす必要があります。
    • ZIP アライメントされている必要があります。
    • その後、パッケージ名や非公開署名キーを変更することはできません(これらのいずれかが変更されている場合、Android パッケージ マネージャーはアップグレードを許可しません)。
    • 50 MB 未満にしてください。
    • 最新バージョンの GDK を使用してコンパイルする必要があります。

認証フローの実装

次の図は、GDK Glassware の基本的な認証フローを示しています。

認証フローを実装するには:

  1. ユーザーが MyGlass で Glassware をオンにすると、認証 URL にリダイレクトされます。これらのリクエストには、後で使用する必要がある userToken という名前のクエリ パラメータが含まれています。

  2. ユーザーが認証ページで認証情報を入力します。

  3. サーバーがユーザーの認証情報を検証します。認証情報が有効な場合は、mirror.accounts.insert メソッドに Mirror API 呼び出しを行います。この方法では、Mirror サービス オブジェクトを作成するときに https://www.googleapis.com/auth/glass.thirdpartyauth スコープを指定する必要があります。未加工の HTTP または Java を使用してこの API 呼び出しを行う例については、アカウント作成の例をご覧ください。

    以下で指定するパラメータとリクエスト本文は、デバイス上で直接アカウントを作成する場合に Android の AccountManager に指定する情報と同じです。

    プロパティ名 説明
    features[] 文字列のリスト 特徴のリスト(AccountManager.hasFeatures を参照)。
    password 文字列 アカウント パスワード(AccountManager.getPassword を参照)。このフィールドにユーザーの実際のパスワードを保存しないことをおすすめします。代わりに、このフィールドを使用して、更新トークンなどの長期間保持される非公開データを保存することをおすすめします。
    userData[] オブジェクトのリスト アカウントに関連付けられたユーザーデータのペア(AccountManager.getUserData を参照)。
    userData[].key 文字列 特定のユーザーデータの Key-Value ペアに関連付けられているキー。
    userData[].value 文字列 特定のユーザーデータ Key-Value ペアに関連付けられた値。
    authTokens[] オブジェクトのリスト アカウントに関連付けられている 1 つ以上の認証トークン(AccountManager.getAuthToken を参照)。
    authTokens[].type 文字列 認証トークンのタイプ。
    authTokens[].authToken 文字列 認証トークン。
  4. mirror.account.insert リクエストを受信すると、Mirror API はアカウントをユーザーの Glass デバイスに push します。このアカウントには、AccountManager クラスを使用してアクセスできます。

ユーザー フレンドリーな認証フローを実装するには、次のガイドラインに従ってください。

  • モバイル デバイス向けにフローを最適化する。
  • フローにはスコープがあり、ユーザーがフローを取り消した場合は、適切に設計されたエラー メッセージを用意します。
  • リクエストしたスコープが実際に Glassware で使用されていることを確認してください。
  • ユーザー アカウントを接続できる場合は、接続していることを確認します。
  • 可能であれば、ユーザーデータはクラウドにバックアップする必要があります。

Glassware 認証の整合性を維持するには、次のいずれかの認証フローを使用します。

アカウントなしのミラーリングまたはハイブリッド

  1. MyGlass で切り替えると、認証用 URL がポップアップで開きます。
  2. これにより、ユーザーは直接スコープに移動して承認できます。
  3. ユーザーがスコープを承認またはキャンセルしたら、ポップアップを閉じます。

アカウントでミラーリングする

  1. MyGlass でオンにすると、認証 URL がポップアップで開きます。
    • ユーザーがすでにサービスにログインしている場合は、ユーザーを直接スコープに誘導します。
    • ユーザーがログインしていない場合は、ログイン フィールドを表示し、サービスにログインできるようにしてから、スコープに送信します。
    • ユーザーがアカウントを持っていない場合は、アカウントを作成するためのリンクを提供します。ユーザーがインストール フロー プロセスの一環としてアカウントを作成する手段を用意する必要があります。
  2. ユーザーがスコープを承認します。
    • Glassware に設定可能な設定がある場合は、適切なデフォルトが選択された設定ページにユーザーを誘導します。
    • Glassware に設定可能な設定がない場合は、ユーザーを確認ページに移動します。追加の構成が不要な場合は、ポップアップを閉じます。

アカウントを使用したハイブリッド

  1. MyGlass でオンにすると、認証 URL がポップアップで開きます。
    • ユーザーがすでにサービスにログインしている場合は、ユーザーを直接スコープに誘導します。
    • ユーザーがログインしていない場合は、ログイン フィールドを表示してログインできるようにし、スコープに送信します。
    • ユーザーがアカウントを持っていない場合は、アカウントを作成するためのリンクを提供します。
  2. ユーザーがスコープを承認します。
  3. Mirror API にリクエストを送信して GDK アカウントを挿入します。
    • 適切なデフォルト値を選択してユーザーを設定ページに誘導します。
    • ユーザーに確認ページを送信します。追加の構成が不要な場合は、ポップアップを閉じます。

アカウントとカスタム スコープを使用したミラーリングまたはハイブリッド

  1. MyGlass でオンにすると、認証 URL がポップアップで開きます。
    • ユーザーがすでにサービスにログインしている場合は、ユーザーを内部スコープに誘導します。
    • ユーザーがログインしていない場合は、ログイン フィールドを表示してログインを許可し、内部スコープに送信します。
    • ユーザーがアカウントを持っていない場合は、アカウントを作成するためのリンクを提供します。
  2. ユーザーがカスタム スコープを承認したら、Google のスコープにユーザーを誘導します。
  3. Mirror API にリクエストを送信して、GDK アカウントを挿入します。
    • 適切なデフォルト値を選択してユーザーを設定ページに誘導します。
    • ユーザーに確認ページを送信します。追加の構成が不要な場合は、ポップアップを閉じます。

Android / iPhone アプリによるミラーリングまたはハイブリッド

  1. MyGlass でオンにすると、認証 URL がポップアップで開きます。
  2. これにより、ユーザーは承認するスコープに直接移動します。
  3. ユーザーがスコープを承認した後:
    • お客様がコンパニオン アプリをお持ちで、認証されている場合は、ポップアップ ウィンドウを閉じます。
    • インストールされていない場合は、Google Play ストアまたは iOS ストアからアプリをダウンロードするようユーザーを誘導するインタースティシャルにユーザーを誘導します。
  4. アプリをインストールして認証したら、ポップアップ ウィンドウを閉じる

GDK、アカウントなし

このフローに必要な作業は、MyGlass で Glassware をオンに切り替えることだけです。

アカウントのある GDK

  1. MyGlass でオンにすると、認証 URL がポップアップで開きます。
    • ユーザーがすでにサービスにログインしている場合は、確認画面にユーザーを誘導します。
    • ユーザーがログインしていない場合は、ログイン フィールドを表示してログインを許可し、確認画面に移動します。
    • ユーザーがアカウントを持っていない場合は、アカウントを作成するためのリンクを提供します。
  2. ユーザーがスコープを承認します。
  3. Mirror API にリクエストを送信して GDK アカウントを挿入します。
  4. 確認画面を表示し、しばらく表示した後に画面を閉じます。

アカウント作成の例

可能な限り、Mirror API のクライアント ライブラリを使用してください。これにより、mirror.accounts.insert を呼び出して簡単にアカウントを作成できます。

未加工の HTTP の例

以下の例では、リクエストの URL と、想定される JSON 本文の例のみを示しています。サービス アカウントに代わって未加工の HTTP リクエストを行うことは、はるかに複雑です(詳しくは、サーバー間アプリケーションでの OAuth 2.0 の使用をご覧ください)。可能であれば、Google API のクライアント ライブラリのいずれかを使用して、この作業を簡素化することをおすすめします。

リクエスト メソッドと URL:

POST https://www.googleapis.com/mirror/v1/accounts/{userToken}/com.example.myapp/username%40email.com

リクエスト本文:

{
    "features": ["a", "b", "c"],
    "userData": [
        { "key": "realName", "value": "Rusty Shackleford" },
        { "key": "foo", "value": "bar" }
    ],
    "authTokens": [
        { "type": "your_token_type", "authToken": "zT419Ma3X2pBr0L..." }
    ]
}

リクエスト URL の {userToken} は、認証フローの実装の手順 1 で認証 URL に渡されたトークンに置き換えます。

Java の例

この例は、Java クライアント ライブラリを使用して mirror.accounts.insert を呼び出す方法を示しています。

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.mirror.Mirror;
import com.google.api.services.mirror.model.Account;
import com.google.api.services.mirror.model.AuthToken;
import com.google.common.collect.Lists;
...

/** Email of the Service Account */
private static final String SERVICE_ACCOUNT_EMAIL =
    "<some-id>@developer.gserviceaccount.com";

/** Path to the Service Account's Private Key file */
private static final String SERVICE_ACCOUNT_PKCS12_FILE_PATH =
    "/path/to/<public_key_fingerprint>-privatekey.p12";

/** The account type, usually based on your company or app's package. */
private static final String ACCOUNT_TYPE = "com.example.myapp";

/** The Mirror API scopes needed to access the API. */
private static final String MIRROR_ACCOUNT_SCOPES =
    "https://www.googleapis.com/auth/glass.thirdpartyauth";

/**
 * Build and returns a Mirror service object authorized with the service accounts.
 *
 * @return Mirror service object that is ready to make requests.
 */
public static Mirror getMirrorService() throws GeneralSecurityException,
    IOException, URISyntaxException {
  HttpTransport httpTransport = new NetHttpTransport();
  JacksonFactory jsonFactory = new JacksonFactory();
  GoogleCredential credential = new GoogleCredential.Builder()
      .setTransport(httpTransport)
      .setJsonFactory(jsonFactory)
      .setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
      .setServiceAccountScopes(MIRROR_ACCOUNT_SCOPES)
      .setServiceAccountPrivateKeyFromP12File(
          new java.io.File(SERVICE_ACCOUNT_PKCS12_FILE_PATH))
      .build();
  Mirror service = new Mirror.Builder(httpTransport, jsonFactory, null)
      .setHttpRequestInitializer(credential).build();
  return service;
}

/**
 * Creates an account and causes it to be synced up with the user's Glass.
 * This example only supports one auth token; modify it if you need to add
 * more than one, or to add features, user data, or the password field.
 *
 * @param mirror the service returned by getMirrorService()
 * @param userToken the user token sent to your auth callback URL
 * @param accountName the account name for this particular user
 * @param authTokenType the type of the auth token (chosen by you)
 * @param authToken the auth token
 */
public static void createAccount(Mirror mirror, String userToken, String accountName,
    String authTokenType, String authToken) {
  try {
    Account account = new Account();
    List<AuthToken> authTokens = Lists.newArrayList(
        new AuthToken().setType(authTokenType).setAuthToken(authToken));
    account.setAuthTokens(authTokens);
    mirror.accounts().insert(
        userToken, ACCOUNT_TYPE, accountName, account).execute();
  } catch (IOException e) {
    e.printStackTrace();
  }
}

Google Pixel Watch でアカウントを取得する

Glass で Account オブジェクトを取得して使用するのは、標準の Android の AccountManager を使用する場合と同様です。

  1. AndroidManifest.xml ファイルで次のマニフェスト権限を宣言します。

    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
    
  2. Glassware のアカウントを取得します。

    AccountManager accountManager = AccountManager.get(mContext);
    // Use your Glassware's account type.
    Account[] accounts = accountManager.getAccountsByType("com.example");
    
    // Pick an account from the list of returned accounts.
    
  3. Account から認証トークンを取得します。

    // Your auth token type.
    final String AUTH_TOKEN_TYPE = "oauth2:https://www.example.com/auth/login";
    
    accountManager.getAuthToken(account, AUTH_TOKEN_TYPE, null, activity, new AccountManagerCallback<Bundle>() {
        public void run(AccountManagerFuture<Bundle> future) {
            try {
                String token = future.getResult().getString(AccountManager.KEY_AUTHTOKEN);
                // Use the token.
            } catch (Exception e) {
                // Handle exception.
            }
        }
    }, null);