[CDK] AppSyncのOIDCプロバイダーにLINEを設定したい

2022.04.29

広島の吉川です。

早速ですが、AWS AppSync APIにLIFFアプリ/LINEミニアプリの認証を設定する方法を紹介します。

環境

  • node 16.13.0
  • typescript 3.9.7
  • aws-cdk 2.20.0
  • aws-cdk-lib 2.20.0
  • @aws-cdk/aws-appsync-alpha 2.20.0
  • constructs 10.0.115

LINE ChannelとLIFF Applicationを作成

LINE Developersより、LINEプロバイダ選択→「Create a new Channel」押下→「LINE Login」押下でChannel新規作成画面を開き、

  • Channel type: 「LINE Login」
  • Provider: 任意
  • Region: 「Japan」
  • Company or owner's country or region: 「Japan」
  • Channel icon: 任意
  • Channel description: 任意
  • App types: 「Web app」+「Mobile app」
  • Email address: 任意
  • Privacy policy URL: 空欄
  • Terms of use URL: 空欄

としてChannelを作成します。

続いてChannelの中にLIFFを作成します。「LIFF」タブを選択→「Add」を押下し、

  • LIFF app name: 任意
  • Size: Full
  • Endpoint URL: https://localhost:5000
  • Scopes: 「openid
  • Bot link feature

としてLIFF Applicationを作成します。Scopesが重要となっており、今回はOIDCを使うのでopenidにチェックを入れておいてください。

上記作成後、

  • LINE Login Channel ID
  • LIFF ID

をそれぞれ控えておきます。

GraphQL Schemaファイル

type User {
  lineUserId: String!
}
type Query {
  findUser: User!
}

DataSourceとするLambda関数コード

「IDトークンから得られたLINEユーザIDを返す」というシンプルなLambda関数を用意します。

// lambda-handler/find-user-handler.ts
import { AppSyncIdentityOIDC, AppSyncResolverEvent } from 'aws-lambda'

export const handler = async (event: AppSyncResolverEvent<{}, {}>) => {
  console.log(JSON.stringify({ event }))

  const lineUserId = (event.identity as AppSyncIdentityOIDC).sub

  return {
    lineUserId,
  }
}

ちなみに、 event 引数をdumpした中身は下のようになります。機密情報は大文字スネークケースの文字列などでマスクしています。

{
  "event": {
    "arguments": {},
    "identity": {
      "claims": {
        "sub": "LINE_USER_ID",
        "aud": "LINE_LOGIN_CHANNEL_ID",
        "amr": ["linesso"],
        "iss": "https://access.line.me",
        "exp": 1234567891,
        "iat": 1234567891
      },
      "issuer": "https://access.line.me",
      "sub": "LINE_USER_ID"
    },
    "以下省略": "..."
  }
}

CDKコード

  • authorizationType: OIDC
  • oidcProvider: 'https://access.line.me'
  • clientId: LINE Login Channel ID

を設定することがポイントとなります。

// lib/appsync-stack.ts
import * as appsync from '@aws-cdk/aws-appsync-alpha'
import * as lambdaNodejs from 'aws-cdk-lib/aws-lambda-nodejs'
import * as cdk from 'aws-cdk-lib'
import { Construct } from 'constructs'

export class AppSyncStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props)

    // AppSyncAPIを作成
    const api = new appsync.GraphqlApi(this, 'myAppsyncApi', {
      name: 'myAppsyncApi',
      schema: appsync.Schema.fromAsset('./schema.graphql'),
      authorizationConfig: {
        defaultAuthorization: {
          authorizationType: appsync.AuthorizationType.OIDC,
          openIdConnectConfig: {
            oidcProvider: 'https://access.line.me',
            clientId: 'LINE_LOGIN_CHANNEL_ID', // LINE Login Channel ID
          },
        },
      },
      xrayEnabled: true,
    })

    // Lambda関数を作成
    const findUserFn = new lambdaNodejs.NodejsFunction(this, 'findUserFn', {
      entry: 'lambda-handler/find-user-handler.ts',
    })

    // Lambda関数をDataSourceとしてAppSyncAPIと紐付ける
    const findUserDs = api.addLambdaDataSource('findUserDs', findUserFn)

    // schema.graphqlで定義した中のどの操作とマッピングするかを指定
    findUserDs.createResolver({
      typeName: 'Query',
      fieldName: 'findUser',
    })
  }
}

動作確認

LIFFアプリを立ち上げてIDトークンを取得

動作確認にあたって、検証用のLINE IDトークンを取得する必要があります。こちらを確認するには、

などからいずれかの方法を採ると良いと思います。

IDトークンを取得できたら、AWSマネジメントコンソールでAppSyncを開きます。左メニューで「クエリ」を選択し、「Authorization Token:」の入力欄にトークンを貼り付けてクエリを実行します。

すると、このようにLINEユーザIDが返ってくることを確認できました。

参考