Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
PHP で学ぶ OAuth 入門
Search
SAW
April 12, 2025
Programming
2
470
PHP で学ぶ OAuth 入門
PHPカンファレンス小田原2025 の発表資料です。
SAW
April 12, 2025
Tweet
Share
More Decks by SAW
See All by SAW
EditorConfig を使ってみよう
azuki
1
76
Symfony でサクッと作る REST API サーバー
azuki
1
140
Vite の Library Mode を使って Vue のコンポーネントをライブラリ化する
azuki
1
180
Laravel や Symfony で手っ取り早く OpenAPI のドキュメントを作成する
azuki
2
280
Provide/Inject で TypeScript の恩恵を受ける方法
azuki
3
140
GraphQL はいいぞ! ~Laravel で学ぶ GraphQL 入門~
azuki
1
360
OSS contributor への第一歩を踏み出すまでの物語
azuki
2
310
Eloquent で relation を扱う基礎
azuki
0
170
メイキング・オブ・PHPカンファレンス 〜PHPカンファレンス関西2024の運営スタッフが語る舞台裏〜
azuki
0
130
Other Decks in Programming
See All in Programming
202507_ADKで始めるエージェント開発の基本 〜デモを通じて紹介〜(奥田りさ)The Basics of Agent Development with ADK — A Demo-Focused Introduction
risatube
PRO
6
1.4k
新世界の理解
koriym
0
130
No Install CMS戦略 〜 5年先を見据えたフロントエンド開発を考える / no_install_cms
rdlabo
0
430
Constant integer division faster than compiler-generated code
herumi
1
140
構文解析器入門
ydah
7
2k
Bedrock AgentCore ObservabilityによるAIエージェントの運用
licux
8
560
変化を楽しむエンジニアリング ~ いままでとこれから ~
murajun1978
0
670
Comparing decimals in Swift Testing
417_72ki
0
160
WebAssemblyインタプリタを書く ~Component Modelを添えて~
ruccho
0
200
実践 Dev Containers × Claude Code
touyu
1
130
Vibe coding コードレビュー
kinopeee
0
410
DynamoDBは怖くない!〜テーブル設計の勘所とテスト戦略〜
hyamazaki
0
180
Featured
See All Featured
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
161
15k
Agile that works and the tools we love
rasmusluckow
329
21k
Imperfection Machines: The Place of Print at Facebook
scottboms
267
13k
Practical Orchestrator
shlominoach
190
11k
Reflections from 52 weeks, 52 projects
jeffersonlam
351
21k
Into the Great Unknown - MozCon
thekraken
40
2k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
29
9.6k
A better future with KSS
kneath
238
17k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
50k
Intergalactic Javascript Robots from Outer Space
tanoku
272
27k
It's Worth the Effort
3n
185
28k
Adopting Sorbet at Scale
ufuk
77
9.5k
Transcript
1)1ͰֶͿ0"VUIೖ 1)1ΧϯϑΝϨϯεখాݪ 4"8
$(whoami) w ࢯ໊Ճ౻फҰ ࡀ w ϋϯυϧωʔϜ4"8 w 9 چ5XJUUFS
!B[VLJ@FBUFS w ؔͷ*5ΤϯδχΞίϛϡχςΟͷ͔͠ ࣗশ w େࡕࡏॅɾѪग़ w ಘҙ8FCΞϓϦέʔγϣϯ։ൃ w -BSBWFM 7VF w ॴଐ༗ݶձࣾΞϦʔϓ 2 چ+*4ϚʔΫ ⁴ ͕ ਓͷԣإʹݟ͑ͨͷ ͚ࣗͩͰͳ͍ͣ ࠓͷ໎ݴ
ඵએ w 1)1ΧϯϑΝϨϯεؔਆށͰ։࠵ w ۚ ɾ w
։࠵ॴਆށӺલݚमηϯλʔ w ઈࢍϓϩϙʔβϧืूத w క ·Ͱ w εϙϯαʔืूத 3 ϓϩϙʔβϧืूϑΥʔϜ εϙϯαʔืूࢿྉ
͜ͷτʔΫͷ֓ཁͱඪ w ೝՄٕज़ͷͭͰ͋Δ0"VUIͷجૅΛઆ໌ w ೝূɾೝՄͷجૅ w 0"VUIͱԿ͔ w 0"VUIͷ͍Ͳ͜Ζ w
؆୯ͳ࣮ྫΛަ͑ͨ0"VUIͷೝՄॲཧͷઆ໌ w ඪ0"VUIͷجૅతͳॲཧͷྲྀΕΛ௫Ή w ʮখాݪͰΈΜͳͰֶ΅͏0"VUIʯˠʮখాݪͰجૅΛֶΜͩ0"VUIʯ 4
ຊτʔΫͷରൣғͱରऀ w ରൣғ0"VUIͷ"VUIPSJ[BUJPO$PEFͷΈ͕ର w جຊతͳॲཧϑϩʔΛத৺ʹઆ໌ w ࣮ફతͳ༰ৄࡉͳ༷ର֎ w ଞͷೝՄ༩ํࣜ *NQMJDJU
$MJFOU$SFEFOUJBMͳͲ ൣғ֎ w ରऀ0"VUIͷجૅʹڵຯͷ͋Δํ w 0"VUIʹ৮Εͨ͜ͱ͕ͳ͍ํ 5
͓͢͢Ίͷࢀߟॻ w 0"VUIపఈೖηΩϡΞͳೝՄγεςϜΛద༻͢ΔͨΊͷݪଇͱ࣮ફ w +VTUJO3JUDIFS "OUPOJP4BOTPஶɾਢాஐ೭༁ ᠳӭࣾ w 0"VUIͷجૅ͔ࣝΒؔ࿈ٕज़·Ͱ৮ΕΒΕ͍ͯΔ w
࣮ྫॆ࣮ ࣮ݴޠ+BWB4DSJQU w ͜ΕҰͰ͔ͳΓֶΔ 6
ೝূɾೝՄͱ0"VUI 7
ೝূͱೝՄ w ೝূ "VUIFOUJDBUJPO w γεςϜʹొ͞Ε͍ͯΔϢʔβʔͷຊਓΛ֬ೝ͢Δॲཧ w ྫ4/4&$αΠτͳͲͷ8FCγεςϜͷϩάΠϯ w
γεςϜʹొ͞Ε͍ͯΔϢʔβʔใͱ߹க͢Δ͜ͱͰγεςϜ͕ར༻Ͱ͖Δ w ೝՄ "VUIPSJ[BUJPO w γεςϜͷػೳϦιʔεͷΞΫηεͷՄ൱Λ੍ޚ͢Δॲཧ w ྫ6/*9ͷϑΝΠϧγεςϜͷύʔϛογϣϯ w ϑΝΠϧͷૢ࡞͕ͦͷϢʔβʔʹରͯ͠ڐՄ͞Ε͍ͯΔ߹ʹͷΈૢ࡞͕Մೳ 8
0"VUIͱ w 0"VUI8FCΞϓϦέʔγϣϯʹ͓͚ΔೝՄͷͨΊͷϓϩτίϧ w SEύʔςΟͷγεςϜ͔Β8FCαʔϏεʹΞΫηε͢Δ͜ͱΛೝՄ w ΞΫηετʔΫϯΛར༻ͯ͠8FCαʔϏεʹΞΫηε w ೝূʹؔ͢ΔϓϩτίϧͰͳ͍͜ͱʹҙ w
ڐՄ͞Εͨݖݶͷൣғ είʔϓ ͰͷΈΞΫηε͕Մೳ w ݖݶͷൣғ8FCαʔϏεͷར༻ऀ͕ڐՄͨ͠ൣғ 9
0"VUIͷར༻ྫ w ESBXJP͔Β(PPHMF%SJWFʹΞΫηε w ESBXJP8FC্Ͱ࡞ਤͰ͖ΔαʔϏε w (PPHMF%SJWF(PPHMFͷΫϥυετϨʔδαʔϏε w ESBXJP͕(PPHMF%SJWFʹٻΊΔΞΫηεݖͷྫ w
ετϨʔδͷϑΝΠϧͷಡΈࠐΈ w ετϨʔδͷϑΝΠϧͷอଘ 10 ESBXJP͔Β(PPHMF%SJWFͷ ΞΫηεͷೝՄΛཁٻ (PPHMF%SJWFͰΞΫηεݖͷೝՄΛ֬ೝ
ͳͥ0"VUI͔ w 8FCαʔϏεͷೝূใΛSEύʔςΟͷγεςϜͱڞ༗͠ͳ͍ w 8FCαʔϏεଆͷೝূใΛมߋͯ͠ӨڹΛड͚ͳ͍ w ͦͦηΩϡϦςΟతʹೝূใΛ֎෦γεςϜͱڞ༗ͨ͘͠ͳ͍ w SEύʔςΟͷγεςϜ͕ཁٻ͢ΔݖݶΛ֬ೝͰ͖Δ w
ཁٻ͞ΕΔݖݶͷ༰͕Ϣʔβʔʹࣔ͞ΕΔ w ϢʔβʔͷڐՄͳ͠ʹݖݶ͕༩͞ΕΔ͜ͱ͕ͳ͍ 11 ESBXJP͕ཁٻ͢Δ(PPHMF%SJWFͷݖݶͷ༰Λ Ϣʔβʔʹ֬ೝ͢Δྫ
0"VUIͷॲཧϑϩʔ 12
0"VUIʹ͓͚Δొਓ w ΫϥΠΞϯτ $MJFOU w อޢରϦιʔεʹΞΫηε͢ΔSEύʔςΟͷιϑτΣΞ w อޢରϦιʔε 1SPUFDUFE3FTPVSDF
w Ϧιʔεॴ༗ऀ͕ΞΫηεݖΛ࣋ͭػೳσʔλͳͲͷϦιʔε w Ϧιʔεॴ༗ऀ 3FTPVSDF0XOFS w อޢରϦιʔεͷΞΫηεݖΛͭϢʔβʔ w ೝՄαʔόʔ "VUIPSJ[BUJPO4FSWFS w Ϧιʔεॴ༗ऀ͕ΫϥΠΞϯτΛೝՄ͢ΔΈΛఏڙ͢ΔγεςϜ 13
ొਓͷ۩ମྫ w ΫϥΠΞϯτESBXJP w อޢରϦιʔε(PPHMF%SJWF"1* w Ϧιʔεॴ༗ऀϒϥβΛૢ࡞͍ͯ͠ΔϢʔβʔ w ೝՄαʔόʔ(PPHMFͷ0"VUIೝՄαʔόʔ 14
0"VUIͷॲཧϑϩʔ Ϧιʔεॴ༗ऀ͕ΫϥΠΞϯτΛೝՄ w ཁٻ͞ΕΔݖݶͷ༰ΛϦιʔεॴ༗ऀʹఏࣔͯ͠ೝՄ͢Δ͔֬ೝ ೝՄαʔόʔೝՄίʔυΛੜ ΫϥΠΞϯτೝՄίʔυ͔ΒΞΫηετʔΫϯΛऔಘ
ΫϥΠΞϯτΞΫηετʔΫϯΛར༻ͯ͠อޢରϦιʔεʹΞΫηε 15
0"VUIͷॲཧϑϩʔ 16 ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ อޢରϦιʔε ΫϥΠΞϯτΛೝՄ
0"VUIͷॲཧϑϩʔ 17 ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ อޢରϦιʔε ೝՄαʔόʔʹϦμΠϨΫτ ೝՄαʔόʔʹϦμΠϨΫτ
0"VUIͷॲཧϑϩʔ 18 ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ อޢରϦιʔε ΞΫηεݖͷೝՄΛ֬ೝ
0"VUIͷॲཧϑϩʔ 19 ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ อޢରϦιʔε ΞΫηεݖΛೝՄ
0"VUIͷॲཧϑϩʔ 20 ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ อޢରϦιʔε ೝՄίʔυΛΫϥΠΞϯτʹ ϦμΠϨΫτ ೝՄίʔυΛ ΫϥΠΞϯτʹ
ϦμΠϨΫτ
0"VUIͷॲཧϑϩʔ 21 ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ อޢରϦιʔε ೝՄίʔυΛ ૹ৴
0"VUIͷॲཧϑϩʔ 22 ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ อޢରϦιʔε ΞΫηετʔΫϯΛ ൃߦ
0"VUIͷॲཧϑϩʔ 23 ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ อޢରϦιʔε ΞΫηετʔΫϯΛਵͯ͠ อޢରϦιʔεʹΞΫηε
0"VUIͷॲཧϑϩʔ 24 ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ อޢରϦιʔε ೝՄ͞ΕͨείʔϓͰ ϦιʔεΛฦ٫
ೝՄίʔυͱΞΫηετʔΫϯ w ೝՄίʔυΞΫηετʔΫϯΛಘΔͨΊͷҰ࣌తͳίʔυ w Ϧιʔεॴ༗ऀʹΑΔΫϥΠΞϯτͷೝՄͷ݁ՌΛࣔ͢ίʔυ w codeͱ͍͏ΫΤϦύϥϝʔλʔΛ༩ͯ͠ΫϥΠΞϯτʹϦμΠϨΫτ w ΞΫηετʔΫϯอޢରϦιʔεͷΞΫηεͰར༻͢ΔτʔΫϯ w
อޢରϦιʔεΞΫηετʔΫϯΛड͚औͬͯݖݶΛ֬ೝͯ͠ϦιʔεΛฦ͢ w อޢରϦιʔεΫϥΠΞϯτ͔Β#FBSFSτʔΫϯͰड͚औΔ 25
είʔϓ w อޢରϦιʔεͷΞΫηεݖΛࣔ͢จࣈྻ w ෳͷείʔϓۭനจࣈ۠ΓʹΑͬͯදݱ͞ΕΔ w ΫϥΠΞϯτ͕ΞΫηεͰ͖ΔൣғείʔϓͰࣔ͞ΕͨൣғͷΈ w Ϧιʔεॴ༗ऀ͕ೝՄ͍ͯ͠ͳ͍είʔϓͷϦιʔεʹΞΫηεෆՄ 26
֤ॲཧϑϩʔͷ࣮ྫ 27
࣮ྫʹ͍ͭͯ w -BSBWFMͷίʔυͷҰ෦Λར༻ͯ͠આ໌ w 8FCαʔόʔͷػೳͳͲ0"VUIͷຊ࣭Ͱͳ͍෦ͷ࣮Λ؆ܿԽ w ෦ॲཧΛӅณ͠ͳ͍ͨΊʹ0"VUIͷϥΠϒϥϦར༻͠ͳ͍ w ࣮ફతͳΞϓϦέʔγϣϯ։ൃͰ0"VUIͷϥΠϒϥϦΛ͏ํ͕ྑ͍ w
0"VUIͷ࣮ʹ͓͍ͯݴޠϑϨʔϜϫʔΫෆ w ཧղͷ͢͠͞Λ༏ઌ w όϦσʔγϣϯͳͲͷ࣮ફతͳ༰লུ 28
࣮ྫͷ֤ߏཁૉͷΞΫηε w Ϧιʔεॴ༗ऀਓؒ ϒϥβ w ΫϥΠΞϯτlocalhost:8000 w ೝՄαʔόʔlocalhost:8001 w
อޢରϦιʔεlocalhost:8002 29
ΫϥΠΞϯτͷೝՄཁٻ w Ϧιʔεॴ༗ऀΛೝՄαʔόʔʹϦμΠϨΫτ w ϦμΠϨΫτ࣌ʹೝՄରͷΫϥΠΞϯτͷใΛΫΤϦύϥϝʔλʹ༩ 30 $query = http_build_query([ 'response_type'
=> 'code', 'client_id' => env('CLIENT_ID'), 'redirect_uri' => 'http://localhost:8000/callback', 'scope' => 'file.read file.write', ]); $authEndpoint = Uri::new('http://localhost:8001/authorize') ->withQuery($query); return redirect()->away($authEndpoint); ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ ೝՄαʔόʔʹ ϦμΠϨΫτ localhost:8000 localhost:8001 ༩ํࣜBVUIPSJ[BUJPODPEF ΫϥΠΞϯτ͕ཁٻ͢Δείʔϓ
ΫϥΠΞϯτͷೝՄͷ֬ೝ w ΫϥΠΞϯτΛೝՄ͢Δ͔Ϧιʔεॴ༗ऀʹ֬ೝ w είʔϓۭനจࣈ۠ΓͰΫΤϦύϥϝʔλͰ͞ΕΔ 31 $clientId = $request->query('client_id'); $client
= Client::find($clientId); // 要求されているスコープを取得 $scope = str($request->query('scope')) ->explode(' ')->filter(); return view('authorize', [ 'client' => $client, 'scope' => $scope, ]); ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτͷ ೝՄΛ֬ೝ localhost:8001
ΫϥΠΞϯτͷೝՄ w ೝՄίʔυΛൃߦͯ͠ΫϥΠΞϯτͷίʔϧόοΫ63-ʹϦμΠϨΫτ w ೝՄίʔυͱϦιʔεॴ༗ऀ͕ڐՄͨ͠είʔϓΛΫΤϦύϥϝʔλͱͯ͠༩ 32 $scope = $request->input('scope'); $authzCode
= Str::random(); $codes[$authzCode] = ['scope' => $scope]; Cache::put('codes', $codes); $callbackUrl = Uri::new($redirectUrl) ->withQuery([ 'scope' => $scope, 'code' => $authzCode, ]); return redirect()->away($callbackUrl); ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ ΫϥΠΞϯτʹ ϦμΠϨΫτ localhost:8000 localhost:8001 ೝՄίʔυΛ༩
τʔΫϯͷऔಘ w ΫϥΠΞϯτೝՄαʔόʔʹೝՄίʔυΛૹ৴ w ΫϥΠΞϯτ#BTJDೝূͰࣝผ w ೝՄαʔόʔΫϥΠΞϯτʹΞΫηετʔΫϯΛൃߦ 33 ೝՄαʔόʔ ΫϥΠΞϯτ
ೝূใͱೝՄίʔυΛ ૹ৴ localhost:8000 localhost:8001 $clientId = $request->getUser(); $clientSecret = $request->getPassword(); $codes = Cache::get('codes'); $code = $codes[$request->input('code')]; // クライアントの情報と認可コードを検証 $token = Str::random(); AccessToken::create(['token' => $token]); return response()->json([ 'access_token' => $token, 'token_type' => 'Bearer', 'scope' => $code['scope'], ]); ΞΫηετʔΫϯΛૹ৴ #BTJDೝূͰΫϥΠΞϯτΛࣝผ
อޢରϦιʔεͷΞΫηε w ΫϥΠΞϯτอޢରϦιʔεʹΞΫηετʔΫϯΛར༻ͯ͠ΞΫηε w ΞΫηετʔΫϯ#FBSFSτʔΫϯͰ͞ΕΔ w อޢରϦιʔεϦιʔεΛΫϥΠΞϯτʹฦ٫ w ೝՄ͞Εͨείʔϓ֎ͷΞΫηεڐՄ͠ͳ͍ 34
ΫϥΠΞϯτ ΞΫηετʔΫϯΛ༩ͯ͠ ϦιʔεʹΞΫηε localhost:8000 localhost:8002 Ϧιʔεͷ༰Λฦ٫ อޢରϦιʔε $token = $request->bearerToken(); $accessToken = AccessToken::whereFirst('token', $token); if ($accessToken?->scope->contains('file.read')) { $content = Storage::json('data.json'); return response()->json($content); } else { return response()->json(null, 403); } #FBSFSτʔΫϯ͔Β ΞΫηετʔΫϯΛऔಘ ΞΫηετʔΫϯʹཁٻ͞ΕΔ είʔϓ͕ଘࡏ͢Δ͔νΣοΫ
མึर͍ w ϦϑϨογϡτʔΫϯΞΫηετʔΫϯΛ࠶ൃߦ͢ΔͨΊͷίʔυ w ༗ޮظݶ͕Εͨ߹ͳͲʹϦιʔεॴ༗ऀʹೝՄΛٻΊΔ͜ͱͳ͘࠶ൃߦ w TUBUF$43'Λ͙ͨΊͷύϥϝʔλʔ w ೝՄίʔυͷૹ৴ݩ͕Ϧιʔεॴ༗ऀ͕ೝՄͨ͠ΫϥΠΞϯτͱಉҰ͔֬ೝ 35
্༷ඞਢͰͳ͍͕ɺηΩϡϦςΟϗʔϧʹͳΔͨΊ ࣄ্࣮ඞਢͷύϥϝʔλͱߟ͑ͨํ͕ྑ͍ ه
·ͱΊ w 0"VUIͷجૅʹ͍ͭͯઆ໌ w ೝূɾೝՄʹ͍ͭͯઆ໌ w 0"VUIͷ֓ཁͱ࣮ྫΛઆ໌ w 0"VUIͷೝՄॲཧϑϩʔʹ͍ͭͯઆ໌ w
֤ཁૉͷॲཧ༰Λ؆୯ͳ࣮ྫΛ༻͍ͯઆ໌ 36
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠