1616
1717class IntrospectionController
1818{
19- /**
20- * @var \Lcobucci\JWT\Parser
21- */
22- private $ jwt ;
23-
24- /**
25- * @var \League\OAuth2\Server\ResourceServer
26- */
27- private $ resourceServer ;
28-
29- /**
30- * @var \Laravel\Passport\Bridge\AccessTokenRepository
31- */
32- private $ accessTokenRepository ;
33-
34- /**
35- * constructing IntrospectionController
36- *
37- * @param \Lcobucci\JWT\Parser $jwt
38- * @param \League\OAuth2\Server\ResourceServer $resourceServer
39- * @param \Laravel\Passport\Bridge\AccessTokenRepository $accessTokenRepository
40- */
41- public function __construct (
42- Parser $ jwt ,
43- ResourceServer $ resourceServer ,
44- AccessTokenRepository $ accessTokenRepository
45- ) {
46- $ this ->jwt = $ jwt ;
47- $ this ->resourceServer = $ resourceServer ;
48- $ this ->accessTokenRepository = $ accessTokenRepository ;
49- }
50-
51- /**
52- * Authorize a client to access the user's account.
53- *
54- * @param ServerRequestInterface $request
55- *
56- * @return JsonResponse|ResponseInterface
57- */
58- public function introspectToken (ServerRequestInterface $ request )
59- {
60- try {
61- $ this ->resourceServer ->validateAuthenticatedRequest ($ request );
62-
63- if (array_get ($ request ->getParsedBody (), 'token_type_hint ' , 'access_token ' ) !== 'access_token ' ) {
64- // unsupported introspection
65- return $ this ->notActiveResponse ();
66- }
67-
68- $ accessToken = array_get ($ request ->getParsedBody (), 'token ' );
69- if ($ accessToken === null ) {
70- return $ this ->notActiveResponse ();
71- }
72-
73- $ token = $ this ->jwt ->parse ($ accessToken );
74- if ( ! $ this ->verifyToken ($ token )) {
75- return $ this ->errorResponse ([
76- 'error ' => [
77- 'title ' => 'Token invalid '
78- ]
79- ]);
80- }
81-
82- /** @var string $userModel */
83- $ userModel = config ('auth.providers.users.model ' );
84- $ user = (new $ userModel )->findOrFail ($ token ->getClaim ('sub ' ));
85-
86- return $ this ->jsonResponse ([
87- 'active ' => true ,
88- 'scope ' => trim (implode (' ' , (array )$ token ->getClaim ('scopes ' , []))),
89- 'client_id ' => intval ($ token ->getClaim ('aud ' )),
90- 'username ' => $ user ->email ,
91- 'token_type ' => 'access_token ' ,
92- 'exp ' => intval ($ token ->getClaim ('exp ' )),
93- 'iat ' => intval ($ token ->getClaim ('iat ' )),
94- 'nbf ' => intval ($ token ->getClaim ('nbf ' )),
95- 'sub ' => intval ($ token ->getClaim ('sub ' )),
96- 'aud ' => intval ($ token ->getClaim ('aud ' )),
97- 'jti ' => $ token ->getClaim ('jti ' ),
98- ]);
99- } catch (OAuthServerException $ oAuthServerException ) {
100- return $ oAuthServerException ->generateHttpResponse (new Psr7Response );
101- } catch (\Exception $ exception ) {
102- return $ this ->exceptionResponse ($ exception );
103- }
104- }
105-
106- /**
107- * returns inactive token message
108- *
109- * @return \Illuminate\Http\JsonResponse
110- */
111- private function notActiveResponse (): JsonResponse
112- {
113- return $ this ->jsonResponse (['active ' => false ]);
114- }
115-
116- /**
117- * @param array|mixed $data
118- * @param int $status
119- *
120- * @return \Illuminate\Http\JsonResponse
121- */
122- private function jsonResponse ($ data , $ status = 200 ): JsonResponse
123- {
124- return new JsonResponse ($ data , $ status );
125- }
126-
127- private function verifyToken (Token $ token ): bool
128- {
129- $ signer = new \Lcobucci \JWT \Signer \Rsa \Sha256 ();
130- $ publicKey = 'file:// ' . Passport::keyPath ('oauth-public.key ' );
131-
132- try {
133- if ( ! $ token ->verify ($ signer , $ publicKey )) {
134- return false ;
135- }
136-
137- $ data = new ValidationData ();
138- $ data ->setCurrentTime (time ());
139-
140- if ( ! $ token ->validate ($ data )) {
141- return false ;
142- }
143-
144- // is token revoked?
145- if ($ this ->accessTokenRepository ->isAccessTokenRevoked ($ token ->getClaim ('jti ' ))) {
146- return false ;
147- }
148-
149- return true ;
150- } catch (\Exception $ exception ) {
151- }
152-
153- return false ;
154- }
155-
156- /**
157- * @param array $data
158- * @param int $status
159- *
160- * @return \Illuminate\Http\JsonResponse
161- */
162- private function errorResponse ($ data , $ status = 400 ): JsonResponse
163- {
164- return $ this ->jsonResponse ($ data , $ status );
165- }
166-
167- /**
168- * returns an error
169- *
170- * @param \Exception $exception
171- * @param int $status
172- *
173- * @return \Illuminate\Http\JsonResponse
174- */
175- private function exceptionResponse (\Exception $ exception , $ status = 500 ): JsonResponse
176- {
177- return $ this ->errorResponse ([
178- 'error ' => [
179- 'id ' => str_slug (get_class ($ exception ) . ' ' . $ status ),
180- 'status ' => $ status ,
181- 'title ' => $ exception ->getMessage (),
182- 'detail ' => $ exception ->getTraceAsString ()
183- ],
184- ], $ status );
185- }
19+ /**
20+ * @var \Lcobucci\JWT\Parser
21+ */
22+ private $ jwt ;
23+
24+ /**
25+ * @var \League\OAuth2\Server\ResourceServer
26+ */
27+ private $ resourceServer ;
28+
29+ /**
30+ * @var \Laravel\Passport\Bridge\AccessTokenRepository
31+ */
32+ private $ accessTokenRepository ;
33+
34+ /**
35+ * constructing IntrospectionController
36+ *
37+ * @param \Lcobucci\JWT\Parser $jwt
38+ * @param \League\OAuth2\Server\ResourceServer $resourceServer
39+ * @param \Laravel\Passport\Bridge\AccessTokenRepository $accessTokenRepository
40+ */
41+ public function __construct (
42+ Parser $ jwt ,
43+ ResourceServer $ resourceServer ,
44+ AccessTokenRepository $ accessTokenRepository
45+ )
46+ {
47+ $ this ->jwt = $ jwt ;
48+ $ this ->resourceServer = $ resourceServer ;
49+ $ this ->accessTokenRepository = $ accessTokenRepository ;
50+ }
51+
52+ /**
53+ * Authorize a client to access the user's account.
54+ *
55+ * @param ServerRequestInterface $request
56+ *
57+ * @return JsonResponse|ResponseInterface
58+ */
59+ public function introspectToken (ServerRequestInterface $ request )
60+ {
61+ try {
62+ $ this ->resourceServer ->validateAuthenticatedRequest ($ request );
63+
64+ if (array_get ($ request ->getParsedBody (), 'token_type_hint ' , 'access_token ' ) !== 'access_token ' ) {
65+ // unsupported introspection
66+ return $ this ->notActiveResponse ();
67+ }
68+
69+ $ accessToken = array_get ($ request ->getParsedBody (), 'token ' );
70+ if ($ accessToken === null ) {
71+ return $ this ->notActiveResponse ();
72+ }
73+
74+ $ token = $ this ->jwt ->parse ($ accessToken );
75+ if (!$ this ->verifyToken ($ token )) {
76+ return $ this ->errorResponse ([
77+ 'error ' => [
78+ 'title ' => 'Token invalid '
79+ ]
80+ ]);
81+ }
82+
83+ /** @var string $userModel */
84+ $ userModel = config ('auth.providers.users.model ' );
85+ $ user = (new $ userModel )->findOrFail ($ token ->getClaim ('sub ' ));
86+
87+ return $ this ->jsonResponse ([
88+ 'active ' => true ,
89+ 'scope ' => trim (implode (' ' , (array )$ token ->getClaim ('scopes ' , []))),
90+ 'client_id ' => intval ($ token ->getClaim ('aud ' )),
91+ 'username ' => $ user ->email ,
92+ 'token_type ' => 'access_token ' ,
93+ 'exp ' => intval ($ token ->getClaim ('exp ' )),
94+ 'iat ' => intval ($ token ->getClaim ('iat ' )),
95+ 'nbf ' => intval ($ token ->getClaim ('nbf ' )),
96+ 'sub ' => intval ($ token ->getClaim ('sub ' )),
97+ 'aud ' => intval ($ token ->getClaim ('aud ' )),
98+ 'jti ' => $ token ->getClaim ('jti ' ),
99+ ]);
100+ } catch (OAuthServerException $ oAuthServerException ) {
101+ return $ oAuthServerException ->generateHttpResponse (new Psr7Response );
102+ } catch (\Exception $ exception ) {
103+ return $ this ->exceptionResponse ($ exception );
104+ }
105+ }
106+
107+ /**
108+ * returns inactive token message
109+ *
110+ * @return \Illuminate\Http\JsonResponse
111+ */
112+ private function notActiveResponse () : JsonResponse
113+ {
114+ return $ this ->jsonResponse (['active ' => false ]);
115+ }
116+
117+ /**
118+ * @param array|mixed $data
119+ * @param int $status
120+ *
121+ * @return \Illuminate\Http\JsonResponse
122+ */
123+ private function jsonResponse ($ data , $ status = 200 ) : JsonResponse
124+ {
125+ return new JsonResponse ($ data , $ status );
126+ }
127+
128+ private function verifyToken (Token $ token ) : bool
129+ {
130+ $ signer = new \Lcobucci \JWT \Signer \Rsa \Sha256 ();
131+ $ publicKey = 'file:// ' . Passport::keyPath ('oauth-public.key ' );
132+
133+ try {
134+ if (!$ token ->verify ($ signer , $ publicKey )) {
135+ return false ;
136+ }
137+
138+ $ data = new ValidationData ();
139+ $ data ->setCurrentTime (time ());
140+
141+ if (!$ token ->validate ($ data )) {
142+ return false ;
143+ }
144+
145+ // is token revoked?
146+ if ($ this ->accessTokenRepository ->isAccessTokenRevoked ($ token ->getClaim ('jti ' ))) {
147+ return false ;
148+ }
149+
150+ return true ;
151+ } catch (\Exception $ exception ) {
152+ }
153+
154+ return false ;
155+ }
156+
157+ /**
158+ * @param array $data
159+ * @param int $status
160+ *
161+ * @return \Illuminate\Http\JsonResponse
162+ */
163+ private function errorResponse ($ data , $ status = 400 ) : JsonResponse
164+ {
165+ return $ this ->jsonResponse ($ data , $ status );
166+ }
167+
168+ /**
169+ * returns an error
170+ *
171+ * @param \Exception $exception
172+ * @param int $status
173+ *
174+ * @return \Illuminate\Http\JsonResponse
175+ */
176+ private function exceptionResponse (\Exception $ exception , $ status = 500 ) : JsonResponse
177+ {
178+ return $ this ->errorResponse ([
179+ 'error ' => [
180+ 'id ' => str_slug (get_class ($ exception ) . ' ' . $ status ),
181+ 'status ' => $ status ,
182+ 'title ' => $ exception ->getMessage (),
183+ 'detail ' => $ exception ->getTraceAsString ()
184+ ],
185+ ], $ status );
186+ }
186187}
0 commit comments