リフレッシュトークン
GoogleアカウントやLINEアカウントなどで、他のアプリのサービスを認証するOAuth 認証を使用している場合、リフレッシュ・トークンを有効にできる。
そもそもトークンとは、ユーザー・クライアントがアクションを実行すべく必要な認証情報である。一般的にjson形式で記述され、JSON Web Token (JWT) と呼ばれる。
アクセストークン(Access Token)
クライアントがリソースに直接、アクセスするために必要な認証情報を保持している。クライアントがサーバーにアクセストークンを渡して、サーバーはそのトークンの情報を解析、クライアントが認可したものかどうかを判断する。アクセストークンには、有効期間があって、存在期間は短い。
リフレッシュトークン(Refresh Token)
リフレッシュ・トークンは、現行のアクセス・トークンが無効または期限切れになったときに新規アクセス・トークンを取得するため、または同じスコープあるいはより狭いスコープの追加アクセス・トークンを取得するために、クライアントに対して発行される。いわば、追加のアクセストークンともいえる。またリフレッシュトークンはアクセスすべきリソースがあるサーバーではなく、認証サーバーに送られる。
リフレッシュトークンは有効 期間が長いため、クライアントがサーバーからリフレッシュトークン取得後、攻撃者が使用できないように、保護する必要がある。アクセストークンも同様だが、存続期間が短いためセキュリティの考慮事項の制限も緩くなる。
OAuth 2.0では、例えばGoogleアカウントやLINEアカウントであるブログサービスなどにログインしたり記事を書いたりする時、GoogleアカウントやLINEアカウントが認証サーバーとして機能し、アクセストークンやリフレッシュトークンを発行しているという構図になる。
Curlでの通信
例えば、パスワードに 'abc' を設定したユーザー 'wang' と、client secretに 'secret' を設定した 'testclient' というクライアントがある場合、以下のように、新しいAccess Token/Refresh Tokenのペアをリクエストすることができる。
$ curl -X POST -H 'Authorization: Basic dGVzdGNsaWVudDpzZWNyZXQ=' -d 'grant_type=password&username=wang&password=abc' localhost:3000/oauth/token { "token_type":"bearer", "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI1NDMsImV4cCI6MTQ0NDI2MjU2M30.MldruS1PvZaRZIJR4legQaauQ3_DYKxxP2rFnD37Ip4", "expires_in":20, "refresh_token":"fdb8fdbecf1d03ce5e6125c067733c0d51de209c" }
Authorization Headerには、client idとclient secretがBASE64でエンコードされている。
$ curl 'localhost:3000/secret?access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI1NDMsImV4cCI6MTQ0NDI2MjU2M30.MldruS1PvZaRZIJR4legQaauQ3_DYKxxP2rFnD37Ip4' This is secret
トークンが切れると・・・
$ curl 'localhost:3000/secret?access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI2MTEsImV4cCI6MTQ0NDI2MjYzMX0.KkHI8KkF4nmi9z6rAQu9uffJjiJuNnsMg1DC3CnmEV0' { "code":401, "error":"invalid_token", "error_description":"The access token provided has expired." }
Googleからのリフレッシュトークン取得までの流れ
- クライアントID
- クライアントシークレット
- リフレッシュトークン
が必要である。
大まかな流れとしては、
- GCPにプロジェクトの作成
- OAuthクライアントID生成(アプリケーションの種類、名前、承認済みのリダイレクトURIは3つは入力することURlはlocal・・・などでいい)
- リダイレクトによる認証コードの取得
である。3では、以下のようなURLをブラウザに貼ってリダイレクト後、表示されたURLの「code=❌❌❌」の❌❌❌がリフレッシュトークンとなる。リダイレクト先では「forbidden」や「接続できません」と出るかもしれないが、それ自体は問題なく、codeの値だけわかればいい。
https://accounts.google.com/o/oauth2/v2/auth? scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.metadata.readonly& access_type=offline& include_granted_scopes=true& redirect_uri=http%3A%2F%2localhost:8080& response_type=code& client_id=上記で取得したクライアントID
取得したリフレッシュトークンは環境変数などに入れて、以下のような感じで(Rubyの例)実装する。
client_id = args.try(:fetch, :client_id, nil) || ENV.fetch('GOOGLE_DRIVE_CLIENT_ID') client_secret = args.try(:fetch, :client_secret, nil) || ENV.fetch('GOOGLE_DRIVE_CLIENT_SECRET') refresh_token = args.try(:fetch, :refresh_token, nil) || ENV.fetch('GOOGLE_DRIVE_REFRESH_TOKEN') @credentials = Google::Auth::UserRefreshCredentials.new( client_id: client_id, client_secret: client_secret, scope: [ 'https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/spreadsheets', ], redirect_uri: 'http://localhost' ) @credentials.refresh_token = refresh_token @credentials.fetch_access_token! @session = GoogleDrive::Session.from_credentials(@credentials)
参考URL