3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AppAuth for Androidを用いてソーシャルログインを実装する

Last updated at Posted at 2022-02-01

前置き

通常、ソーシャルログインを実装するのに、そのソーシャルログインのSDKを導入することが一般的です。しかし、この方法ですと、SDKに依存してしまうため、対象プラットフォームのSDKがなければ、導入ができなくなります。たとえば、

  • HMSのAndroid端末において、Google IDまたはApple IDでログインする場合
  • HMS Coreが入っていないAndroid端末において、HUAWEI IDでログインする場合
  • GMSのAndroid端末において、Apple IDでログインする場合

上記の状況ですと、SDK導入によるソーシャルログインの実装では対応が不可能です。

また、SDKはプラットフォームごとに異なるため、ソースコードの管理において手間が増えます。

そこで、解決策としてOauthが出てきます。Oauthを利用すれば、プラットフォームとソーシャルログインSDKに依存せずに、ソーシャルログインを実装できます。

Android端末限定であれば、AppAuth for AndroidというOauthに特化したAndroid専用のSDKあり、それを使えば、OAuth 2.0に対応したソーシャルログインを簡単に実装できます。

AppAuth for Androidの導入方法

対応OS

  • Android 6.0以上

ライブラリの導入

appモジュールのbuild.gradleに

  1. AppAuth for Androidnet.openid:appauth
  2. JWT Decoding library for Androidcom.auth0.android:jwtdecode
    を追加します。

AppAuth for Androidを使ってソーシャルログインをし、JWT Decoding library for Androidを使ってログイン後に返ってくるIDトークンを解凍し、ユーザー情報を取得します。

build.gradle
// AppAuth SDK
implementation 'net.openid:appauth:{バージョン}'
// For decode ID Token
implementation 'com.auth0.android:jwtdecode:{バージョン}'

また、それぞれの最新バージョンはこちらでご確認ください。
AppAuth for Androidの最新バージョン
JWT Decoding library for Androidの最新バージョン

AndroidManifest.xmlの編集

AndroidManifest.xmlに次のようにリダイレクト用のactivityを追加します。

AndroidManifest.xml
...
<activity
        android:name="net.openid.appauth.RedirectUriReceiverActivity"
        tools:node="replace">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme="{your scheme}"
              android:host="{your host}"
              android:path="{your path}"/>
    </intent-filter>
</activity>
...

<data>要素の中身は対象のソーシャルログインによって異なります。たとえば、

Google ID

<data android:scheme="{アプリのパッケージ名}"/>

HUAWEI ID

<data android:scheme="com.huawei.apps.{OAuth 2.0 client ID}"/>

Apple ID

<data android:scheme="https"
      android:host="{Developerサイトへ事前に登録したReturnURLsのホスト部分}"
      android:path="{Developerサイトへ事前に登録したReturnURLsのパス部分}"/>

LINE ID

<data android:scheme="https"
      android:host="{LINE Developersコンソールに登録したコールバックURLのホスト部分}"
      android:path="{LINE Developersコンソールに登録したコールバックURLのパス部分}"/>

Facebook ID

<data android:scheme="https"
      android:host="{クライアントOAuth設定に登録した有効なOAuthリダイレクトURIのホスト部分}"
      android:path="{クライアントOAuth設定に登録した有効なOAuthリダイレクトURIのパス部分}"/>

AuthStateとAuthorizationServiceConfigurationを用意

空のAuthStateを生成し、ソーシャルログインの認証エンドポイントとトークンエンドポイントを用いてAuthorizationServiceConfigurationを生成します。

private val appAuthState: AuthState = AuthState.jsonDeserialize("{}")
private val config = AuthorizationServiceConfiguration(
    Uri.parse({認証エンドポイント}),
    Uri.parse({クンエンドポイント})
)

サインイン

サインイン画面を表示

  1. ソーシャルログインのクライアントIDとリダイレクトURIと、前のステップで生成したAuthorizationServiceConfigurationを用いて、AuthorizationRequestを生成します。
  2. スコープを設定します。
  3. AuthorizationServiceのgetAuthorizationRequestIntentで、サインインのIntentを作ります。
  4. startActivityForResultでサインインのIntentを起動します。サインインの結果はonActivityResultで返ってくるので、startActivityではなく、startActivityForResultでIntentを起動しなければなりません。
fun signIn() {
    val authorizationRequest = AuthorizationRequest
        .Builder(
            config,
            {シャルログインのクライアントID},
            ResponseTypeValues.CODE,
            Uri.parse({シャルログインのクライアントのリダイレクトURI})
        )
        .setScope({スコプ。例:openid email profile})
        .build()
    val intent = AuthorizationService(context).getAuthorizationRequestIntent(authorizationRequest)
    startActivityForResult(intent, requestCode)
}

サインインの認証結果を取得

  1. onActivityResultでサインインの認証結果を受け取ります。
  2. AuthStateを更新します。

認証成功の条件
AuthorizationResponseが空ではなく、かつAuthorizationExceptionが空である

認証失敗の条件
AuthorizationResponseが空、またはAuthorizationExceptionが空ではない

fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    val authorizationResponse = AuthorizationResponse.fromIntent(data)
    val exception = AuthorizationException.fromIntent(data)
    appAuthState.update(authorizationResponse, exception)

    if (exception != null || authorizationResponse == null) {
        // 認証失敗
    } else {
        // 認証成功
    }
}

各トークンを取得

  1. AuthorizationResponseを使ってトークンを要求します。
  2. (1)のレスポンスを使ってAuthStateを更新します。
  3. AuthStateのaccessTokenにアクセストークンが入っています。
  4. AuthStateのrefreshTokenにリフレッシュトークンが入っています。
  5. AuthStateのidTokenにIDトークンが入っています。
AuthorizationService(context)
    .performTokenRequest(authorizationResponse.createTokenExchangeRequest()) { tokenResponse, authorizationException ->
        appAuthState.update(tokenResponse, authorizationException)
        tokenResponse?.let {
            // アクセストークン=appAuthState.accessToken
            // リフレッシュトークン=appAuthState.refreshToken
            // IDトークン=appAuthState.idToken
        }
    }

IDトークンをユーザー情報に変換

  1. JWTでIDトークンを解凍します。
  2. OpenID=jwt.subject
  3. メールアドレス=jwt.claims["email"]?.asString()
val jwt = JWT(idToken)
val openId = jwt.subject
val email = jwt.claims["email"]?.asString()

GitHub

AppAuthDemo(Huawei Google)

参考

AppAuth for Android

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?