@@ -60,18 +60,10 @@ public function refresh(array $claims) {
6060 if (time () < $ claims ['expires ' ]) return null ;
6161
6262 // Refresh token
63- $ result = $ this ->backend ->acquire ([
63+ return ByAccessToken:: from ( $ this ->backend ->acquire ([
6464 'grant_type ' => 'refresh_token ' ,
6565 'refresh_token ' => $ claims ['refresh ' ],
66- ]);
67- return new ByAccessToken (
68- $ result ['access_token ' ],
69- $ result ['token_type ' ] ?? 'Bearer ' ,
70- $ result ['scope ' ] ?? null ,
71- $ result ['expires_in ' ] ?? null ,
72- $ result ['refresh_token ' ] ?? null ,
73- $ result ['id_token ' ] ?? null
74- );
66+ ]));
7567 }
7668
7769 /**
@@ -84,36 +76,36 @@ public function refresh(array $claims) {
8476 * @throws lang.IllegalStateException
8577 */
8678 public function authenticate ($ request , $ response , $ session ) {
87- $ stored = $ session ->value ($ this ->namespace );
79+ $ stored = $ session ->value ($ this ->namespace ) ?? [ ' state ' => []] ;
8880
89- // We have an access token, reset state and return an authenticated session
90- // See https://www.oauth.com/oauth2-servers/access-tokens/access-token-response/
91- // and https://tools.ietf.org/html/rfc6749#section-5.1
81+ // We have an access token, remove and return an authenticated session. The
82+ // authentication implementation registers the user and transmits the session.
9283 if ($ token = $ stored ['token ' ] ?? null ) {
9384 unset($ stored ['token ' ]);
9485 $ session ->register ($ this ->namespace , $ stored );
9586
96- return new ByAccessToken (
97- $ token ['access_token ' ],
98- $ token ['token_type ' ] ?? 'Bearer ' ,
99- $ token ['scope ' ] ?? null ,
100- $ token ['expires_in ' ] ?? null ,
101- $ token ['refresh_token ' ] ?? null ,
102- $ token ['id_token ' ] ?? null
103- );
87+ return ByAccessToken::from ($ token );
10488 }
10589
90+ // Enter authentication flow, resolving callback URI against the curren request.
10691 $ uri = $ this ->url (true )->resolve ($ request );
10792 $ callback = $ this ->callback ? $ uri ->resolve ($ this ->callback ) : $ this ->service ($ uri );
10893
109- // Start authorization flow to acquire an access token
110- $ server = $ request ->param ('state ' );
111- if (null === $ server || null === $ stored ) {
94+ // Check whether we are continuing an existing authentication flow based on the
95+ // state given by the server and our session; or if we need to start a new one.
96+ // Handle deprecated session layouts from previous library versions.
97+ sscanf ($ request ->param ('state ' ) ?? '' , self ::STATE , $ state , $ fragment );
98+ $ flow = (
99+ $ stored ['flows ' ][$ state ] ??
100+ (isset ($ stored ['flow ' ][$ state ]) ? ['uri ' => $ stored ['flow ' ][$ state ], 'seed ' => []] : null ) ??
101+ (isset ($ stored ['target ' ]) ? ['uri ' => $ stored ['target ' ], 'seed ' => []] : null )
102+ );
103+
104+ if (null === $ flow ) {
112105 $ state = bin2hex ($ this ->rand ->bytes (16 ));
113106 $ seed = $ this ->backend ->seed ();
114107
115- $ stored ??= ['flow ' => []];
116- $ stored ['flow ' ][$ state ]= ['uri ' => (string )$ uri , 'seed ' => $ seed ];
108+ $ stored ['flows ' ][$ state ]= ['uri ' => (string )$ uri , 'seed ' => $ seed ];
117109 $ session ->register ($ this ->namespace , $ stored );
118110 $ session ->transmit ($ response );
119111
@@ -128,59 +120,34 @@ public function authenticate($request, $response, $session) {
128120 $ target = $ this ->auth ->using ()->params ($ this ->backend ->pass ($ params , $ seed ))->create ();
129121
130122 // If a URL fragment is present, append it to the state parameter, which
131- // is passed as the last parameter to the authentication service.
132- $ this ->redirect ($ response , $ target , sprintf ('
133- var target = "%1$s";
134- var hash = document.location.hash.substring(1);
135-
123+ // is always passed as the last parameter to the authentication service.
124+ $ separator = self ::FRAGMENT ;
125+ return $ this ->redirect ($ response , $ target , <<<JS
126+ var hash = document.location.hash;
136127 if (hash) {
137- document.location.replace(target + "%2$s" + encodeURIComponent(hash));
128+ document.location.replace(' { $ target}{ $ separator } ' + encodeURIComponent(hash.substring(1) ));
138129 } else {
139- document.location.replace(target);
140- } ' ,
141- $ target ,
142- self ::FRAGMENT
143- ));
144- return null ;
145- }
130+ document.location.replace(' {$ target }');
131+ }
132+ JS
133+ );
134+ } else {
146135
147- // Continue authorization flow, handling previous session layout
148- $ state = explode (self ::FRAGMENT , $ server );
149- if (
150- ($ target = $ stored ['flow ' ][$ state [0 ]] ?? null ) ||
151- (($ target = $ stored ['target ' ] ?? null ) && ($ state [0 ] === $ stored ['state ' ]))
152- ) {
153- unset($ stored ['flow ' ][$ state [0 ]]);
154-
155- // Target is an array for old session layout and during transition
156- if (is_array ($ target )) {
157- $ uri = $ target ['uri ' ];
158- $ seed = $ target ['seed ' ];
159- } else {
160- $ uri = $ target ;
161- $ seed = [];
162- }
163-
164- // Exchange the auth code for an access token
136+ // Exchange the auth code for an access token, then remove the stored state.
165137 $ params = [
166138 'grant_type ' => 'authorization_code ' ,
167139 'code ' => $ request ->param ('code ' ),
168140 'redirect_uri ' => $ callback ,
169- 'state ' => $ server
141+ 'state ' => $ state
170142 ];
171- $ stored ['token ' ]= $ this ->backend ->acquire ($ params , $ seed );
143+ $ stored ['token ' ]= $ this ->backend ->acquire ($ params , $ flow ['seed ' ]);
144+
145+ unset($ stored ['flows ' ][$ state ], $ stored ['flow ' ][$ state ]);
172146 $ session ->register ($ this ->namespace , $ stored );
173147 $ session ->transmit ($ response );
174148
175149 // Redirect to self, using encoded fragment if present
176- $ this ->finalize ($ response , $ uri .(isset ($ state [1 ]) ? '# ' .urldecode ($ state [1 ]) : '' ));
177- return null ;
150+ return $ this ->finalize ($ response , $ flow ['uri ' ].(isset ($ fragment ) ? '# ' .urldecode ($ fragment ) : '' ));
178151 }
179-
180- throw new IllegalStateException (sprintf (
181- 'Flow error, unknown server state %s expecting one of %s ' ,
182- $ state [0 ],
183- implode (', ' , array_keys ($ stored ['flow ' ] ?? [$ stored ['state ' ] => true ]))
184- ));
185152 }
186153}
0 commit comments