Skip to content

Commit 3339d07

Browse files
Update examples for GET /access/jwt deprecation (#34)
* Update examples to include JWT generation only All the examples previously used redirects which would trigger a GET /access/jwt request with the JWT in the url string. To enhance security, we are deprecating the GET /jwt endpoint in favor of POST /access/jwt with the JWT in the body of the request which must be initiated from the browser to ensure that cookies are set properly and that redirects work correctly. * Add JWT hidden form submission examples The JWT must be submitted via a form submission as other POST requests such as those generated by AJAX, axios, or fetch will be blocked by CORS.
1 parent 0e40e0f commit 3339d07

24 files changed

+375
-575
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
The files in this repository are examples and not guaranteed to run or be correct. They should explain you how you can make Zendesk SSO work with JWT from your stack. Pull requests much appreciated.
44

5+
The `jwt_generation` folder contains examples on how to generate JWTs. You can generate JWTs on your server and return it to your client. You may also want to return the Zendesk JWT URL with your subdomain to prevent hardcoding it in your client code.
6+
7+
The `form_submission` folder contains examples of how to trigger the POST request with the JWT in the body of the request. This must be done via form submission as other methods of creating POST requests such as axios or fetch will be blocked by CORS.
8+
59
## Documentation
610

711
Further documentation on JWT based Zendesk SSO is available [in our knowledge base](https://support.zendesk.com/hc/en-us/articles/4408845838874-Enabling-JWT-single-sign-on)

c_sharp_handler.cs

Lines changed: 0 additions & 48 deletions
This file was deleted.

classic_asp_jwt.asp

Lines changed: 0 additions & 26 deletions
This file was deleted.

classic_asp_jwt_with_ad.asp

Lines changed: 0 additions & 153 deletions
This file was deleted.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<html>
2+
<script>
3+
function handleLogin(event) {
4+
event.preventDefault();
5+
// handle authenticating the user in your system and return the generated JWT
6+
7+
// (Assuming AJAX successfully returns a JWT)
8+
// On Success - Add the JWT to a hidden form and submit
9+
document.getElementById('jwtInput').value = response.data.jwt; // Extract the JWT from the response
10+
document.forms['jwtForm'].submit();
11+
}
12+
</script>
13+
...
14+
<div>
15+
<form id="yourLoginForm" onsubmit="handleLogin()">
16+
...
17+
</form>
18+
<form id="jwtForm" method="post" action="https://{YOUR_ZENDESK_SUBDOMAIN}.zendesk.com/access/jwt">
19+
<input id="jwtInput" type="hidden" name="jwt" />
20+
</form>
21+
</div>
22+
</html>

form_submission/jquery_xhr_jwt.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// make the request to your login service
2+
function handleLogin() {
3+
const xhr = jQuery.post("/internal/login", $("#yourLoginForm").serialize());
4+
5+
xhr.success(function(data) {
6+
// On successful login - add JWT to a hidden form and submit
7+
// Return the JWT generated from your sever and the Zendesk
8+
// JWT URL, usually in the format of
9+
// https://{your_subdomain}.zendesk.com/access/jwt
10+
var form = $('<form />').attr("method", "POST").
11+
attr("action", data['url'] + window.location.search);
12+
13+
$('<input />').attr("type", "hidden").
14+
attr("name", "jwt").
15+
attr("value", data['jwt']).
16+
appendTo(form);
17+
18+
form.appendTo('body');
19+
form.submit();
20+
}).fail(function() {
21+
// Handle login failures
22+
alert("Authentication failed");
23+
});
24+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
class JwtController < ApplicationController
2+
...
3+
ZENDESK_SUBDOMAIN = ENV['ZENDESK_SUBDOMAIN']
4+
# Zendesk will pass various params when redirecting you to your remote login URL
5+
JWT_PARAMS = %i[return_to brand_id locale_id timestamp].freeze
6+
...
7+
8+
def create
9+
if (user = User.authenticate(params[:login], params[:password]))
10+
# Use your implemented JWT generation code. See ../jwt_generation/ruby_on_rails_jwt.rb for an example
11+
@jwt = generate_jwt(user.name, user.email)
12+
# handle any JWT generation errors
13+
14+
jwt_params = params.slice(*JWT_PARAMS).permit(*JWT_PARAMS)
15+
# Ensure parameters that Zendesk passed to your remote login page are preserved
16+
@url = "https://#{ZENDESK_SUBDOMAIN}.zendesk.com/access/jwt?#{jwt_params.to_query}"
17+
18+
render :create
19+
else
20+
render :new, notice: 'Invalid credentials'
21+
end
22+
end
23+
...
24+
end
25+
26+
# jwt/create.html.erb
27+
<%= javascript_tag do %>
28+
window.onload = function(){
29+
document.forms['jwt_form'].submit();
30+
}
31+
<% end %>
32+
33+
<%= form_with url: @url, html: { id: 'jwt_form' } do |f| %>
34+
<%= f.hidden_field :jwt, value: @jwt %>
35+
<% end %>

form_submission/react_jwt.jsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { useRef } from 'react'
2+
3+
const YOUR_ZENDESK_SUBDOMAIN = 'subdomain'
4+
5+
function App() {
6+
const formRef = useRef(null);
7+
const inputRef = useRef(null);
8+
9+
const handleClick = async () => {
10+
const response = await handleYourLogin()
11+
// on successful user authentication, pass the JWT in the response
12+
// extract the JWT from the response data
13+
const jwt = response.data.jwt
14+
15+
// add the JWT to a hidden form on your login page
16+
inputRef.current.value = jwt
17+
18+
formRef.current.submit()
19+
}
20+
21+
return (
22+
<div>
23+
<YourLoginForm>
24+
...
25+
<button
26+
onClick={handleClick}
27+
>
28+
Log in
29+
</button>
30+
</YourLoginForm>
31+
<form ref={formRef} action={`https://${YOUR_ZENDESK_SUBDOMAIN}.zendesk.com/access/jwt`} method="post">
32+
<input ref={inputRef} type="hidden" name="jwt"></input>
33+
</form>
34+
</div>
35+
);
36+
}
37+
38+
export default App;

0 commit comments

Comments
 (0)