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
240
PHP で学ぶ OAuth 入門
PHPカンファレンス小田原2025 の発表資料です。
SAW
April 12, 2025
Tweet
Share
More Decks by SAW
See All by SAW
EditorConfig を使ってみよう
azuki
1
58
Symfony でサクッと作る REST API サーバー
azuki
1
99
Vite の Library Mode を使って Vue のコンポーネントをライブラリ化する
azuki
1
130
Laravel や Symfony で手っ取り早く OpenAPI のドキュメントを作成する
azuki
2
240
Provide/Inject で TypeScript の恩恵を受ける方法
azuki
3
120
GraphQL はいいぞ! ~Laravel で学ぶ GraphQL 入門~
azuki
1
330
OSS contributor への第一歩を踏み出すまでの物語
azuki
2
280
Eloquent で relation を扱う基礎
azuki
0
150
メイキング・オブ・PHPカンファレンス 〜PHPカンファレンス関西2024の運営スタッフが語る舞台裏〜
azuki
0
120
Other Decks in Programming
See All in Programming
LRパーサーはいいぞ
ydah
7
1.4k
The New Developer Workflow: How AI Transforms Ideas into Code
danielsogl
0
140
事業KPIを基に価値の解像度を上げる
nealle
0
120
Rubyの!メソッドをちゃんと理解する
alstrocrack
1
310
ASP.NETアプリケーションのモダナイゼーションについて
tomokusaba
0
260
マイコンでもRustのtestがしたい/KernelVM Kansai 11
tnishinaga
1
900
2025-04-25 GitHub Copilot Agent ライブデモ(スクリプト)
goataka
0
120
eBPF超入門「o11yに使える」とは (20250424_eBPF_o11y)
thousanda
1
120
「MCPを使ってる人」が より詳しくなるための解説
yamaguchidesu
0
190
読書シェア会 vol.4 『ダイナミックリチーミング 第2版』
kotaro666
0
110
iOSアプリで測る!名古屋駅までの 方向と距離
ryunakayama
0
160
最速Green Tea 🍵 Garbage Collector
kuro_kurorrr
1
130
Featured
See All Featured
A Modern Web Designer's Workflow
chriscoyier
693
190k
Adopting Sorbet at Scale
ufuk
76
9.4k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
48
5.4k
How STYLIGHT went responsive
nonsquared
100
5.5k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
34
3k
The Invisible Side of Design
smashingmag
299
50k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
227
22k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
Visualization
eitanlees
146
16k
[RailsConf 2023] Rails as a piece of cake
palkan
54
5.5k
Building a Scalable Design System with Sketch
lauravandoore
462
33k
The Cult of Friendly URLs
andyhume
78
6.4k
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
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠