public static ReadOnlyJWTClaimsSet decodeToken(String authHeader)
     throws ParseException, JOSEException {
   SignedJWT signedJWT = SignedJWT.parse(getSerializedToken(authHeader));
   if (signedJWT.verify(new MACVerifier(TOKEN_SECRET))) {
     return signedJWT.getJWTClaimsSet();
   } else {
     throw new JOSEException("Signature verification failed");
   }
 }
  private Pair<LogoutSuccessResponse, Cookie> processInternal() throws ServerException {
    String sessionIdString =
        this.httpRequest.getCookieValue(Shared.getSessionCookieName(this.tenantInfo.getName()));
    SessionID sessionId = null;
    SessionManager.Entry entry = null;
    if (sessionIdString != null) {
      sessionId = new SessionID(sessionIdString);
      entry = this.sessionManager.get(sessionId);
    }

    SignedJWT idTokenJwt = this.logoutRequest.getIDTokenHint().getSignedJWT();

    boolean validSignature;
    try {
      validSignature = idTokenJwt.verify(new RSASSAVerifier(this.tenantInfo.getPublicKey()));
    } catch (JOSEException e) {
      throw new ServerException(
          OAuth2Error.SERVER_ERROR.setDescription("error while verifying id_token signature"), e);
    }
    if (!validSignature) {
      throw new ServerException(
          OAuth2Error.INVALID_REQUEST.setDescription("id_token has an invalid signature"));
    }

    ReadOnlyJWTClaimsSet idTokenClaimsSet;
    try {
      idTokenClaimsSet = idTokenJwt.getJWTClaimsSet();
    } catch (ParseException e) {
      throw new ServerException(
          OAuth2Error.INVALID_REQUEST.setDescription("failed to parse claims out of id_token"), e);
    }

    ErrorObject error = validateIdTokenClaims(idTokenClaimsSet, entry);
    if (error != null) {
      throw new ServerException(error);
    }

    ClientID clientId = new ClientID(idTokenClaimsSet.getAudience().get(0));
    ClientInfo clientInfo =
        this.clientInfoRetriever.retrieveClientInfo(this.tenantInfo.getName(), clientId);
    if (clientInfo.getCertSubjectDn() != null) {
      if (this.logoutRequest.getClientAssertion() != null) {
        this.solutionUserAuthenticator.authenticateByClientAssertion(
            this.logoutRequest.getClientAssertion(),
            REQUEST_LIFETIME_MS,
            this.httpRequest.getRequestUrl(),
            this.tenantInfo,
            clientInfo);
      } else {
        throw new ServerException(
            OAuth2Error.INVALID_CLIENT.setDescription(
                "client_assertion parameter is required since client has registered a cert"));
      }
    }

    if (this.logoutRequest.getPostLogoutRedirectionURI() != null) {
      if (!clientInfo
          .getPostLogoutRedirectUris()
          .contains(this.logoutRequest.getPostLogoutRedirectionURI())) {
        throw new ServerException(
            OAuth2Error.INVALID_REQUEST.setDescription("unregistered post_logout_redirect_uri"));
      }
    }

    // SLO using OpenID Connect HTTP-Based Logout 1.0 - draft 03
    // construct iframe links containing logout_uri requests, the browser will send these to other
    // participating clients
    // do not include the client that initiated this logout request as that client has already
    // logged out before sending us this request
    Set<URI> logoutUris = new HashSet<URI>();
    if (entry != null) {
      for (ClientInfo client : entry.getClients()) {
        if (client.getLogoutUri() != null && !client.getID().equals(clientId)) {
          logoutUris.add(client.getLogoutUri());
        }
      }
      this.sessionManager.remove(sessionId);
    }

    return Pair.of(
        new LogoutSuccessResponse(
            this.logoutRequest.getPostLogoutRedirectionURI(),
            this.logoutRequest.getState(),
            sessionId,
            logoutUris),
        (sessionId == null) ? null : wipeOutSessionCookie());
  }