@@ -29,6 +29,7 @@ var AuthenticationRequest = require('./AuthenticationRequest');
2929var AuthenticationResponse = require ( './AuthenticationResponse' ) ;
3030var RelyingPartySchema = require ( './RelyingPartySchema' ) ;
3131var onHttpError = require ( './onHttpError' ) ;
32+ var FormUrlEncoded = require ( './FormUrlEncoded' ) ;
3233
3334/**
3435 * RelyingParty
@@ -263,9 +264,113 @@ var RelyingParty = function (_JSONDocument) {
263264 }
264265 }
265266
267+ /**
268+ * logoutRequest
269+ *
270+ * Composes and returns the logout request URI, based on the OP's
271+ * `end_session_endpoint`, with appropriate parameters.
272+ *
273+ * Note: Calling client code has the responsibility to clear the local
274+ * session state (for example, by calling `rp.clearSession()`). In addition,
275+ * some IdPs (such as Google) may not provide an `end_session_endpoint`,
276+ * in which case, this method will return null.
277+ *
278+ * @see https://openid.net/specs/openid-connect-session-1_0.html#RPLogout
279+ *
280+ * @throws {Error } If provider config is not initialized
281+ *
282+ * @throws {Error } If `post_logout_redirect_uri` was provided without a
283+ * corresponding `id_token_hint`
284+ *
285+ * @param [options={ }] {object}
286+ *
287+ * @param [options.id_token_hint] {string} RECOMMENDED.
288+ * Previously issued ID Token passed to the logout endpoint as
289+ * a hint about the End-User's current authenticated session with the
290+ * Client. This is used as an indication of the identity of the End-User
291+ * that the RP is requesting be logged out by the OP. The OP *need not* be
292+ * listed as an audience of the ID Token when it is used as an
293+ * `id_token_hint` value.
294+ *
295+ * @param [options.post_logout_redirect_uri] {string} OPTIONAL. URL to which
296+ * the RP is requesting that the End-User's User Agent be redirected after
297+ * a logout has been performed. The value MUST have been previously
298+ * registered with the OP, either using the `post_logout_redirect_uris`
299+ * Registration parameter or via another mechanism. If supplied, the OP
300+ * SHOULD honor this request following the logout.
301+ *
302+ * Note: The requirement to validate the uri for previous registration means
303+ * that, in practice, the `id_token_hint` is REQUIRED if
304+ * `post_logout_redirect_uri` is used. Otherwise, the OP has no way to get
305+ * the `client_id` to load the saved client registration, to validate the
306+ * uri. The only way it can get it is by decoding the `id_token_hint`.
307+ *
308+ * @param [options.state] {string} OPTIONAL. Opaque value used by the RP to
309+ * maintain state between the logout request and the callback to the
310+ * endpoint specified by the `post_logout_redirect_uri` query parameter. If
311+ * included in the logout request, the OP passes this value back to the RP
312+ * using the `state` query parameter when redirecting the User Agent back to
313+ * the RP.
314+ *
315+ * TODO: In the future, consider adding `response_mode` param, for the OP to
316+ * determine how to return the `state` back the RP.
317+ * @see http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes
318+ *
319+ * TODO: Handle special cases for popular providers (Google, MSFT)
320+ *
321+ * @returns {string|null } Logout uri (or null if no end_session_endpoint was
322+ * provided in the IdP config)
323+ */
324+
325+ } , {
326+ key : 'logoutRequest' ,
327+ value : function logoutRequest ( ) {
328+ var options = arguments . length > 0 && arguments [ 0 ] !== undefined ? arguments [ 0 ] : { } ;
329+ var id_token_hint = options . id_token_hint ,
330+ post_logout_redirect_uri = options . post_logout_redirect_uri ,
331+ state = options . state ;
332+
333+ var configuration = void 0 ;
334+
335+ assert ( this . provider , 'OpenID Configuration is not initialized' ) ;
336+ configuration = this . provider . configuration ;
337+ assert ( configuration , 'OpenID Configuration is not initialized' ) ;
338+
339+ if ( ! configuration . end_session_endpoint ) {
340+ console . log ( 'OpenId Configuration for ' + ( configuration . issuer + ' is missing end_session_endpoint' ) ) ;
341+ return null ;
342+ }
343+
344+ if ( post_logout_redirect_uri && ! id_token_hint ) {
345+ throw new Error ( 'id_token_hint is required when using post_logout_redirect_uri' ) ;
346+ }
347+
348+ var params = { } ;
349+
350+ if ( id_token_hint ) {
351+ params . id_token_hint = id_token_hint ;
352+ }
353+ if ( post_logout_redirect_uri ) {
354+ params . post_logout_redirect_uri = post_logout_redirect_uri ;
355+ }
356+ if ( state ) {
357+ params . state = state ;
358+ }
359+
360+ var url = new URL ( configuration . end_session_endpoint ) ;
361+ url . search = FormUrlEncoded . encode ( params ) ;
362+
363+ return url . href ;
364+ }
365+
266366 /**
267367 * Logout
268368 *
369+ * @deprecated
370+ *
371+ * TODO: Add deprecation warnings, then remove. Client code should
372+ * use `logoutRequest()` instead
373+ *
269374 * @returns {Promise }
270375 */
271376
0 commit comments