Assuming we’ve set up a basic, test endpoint on Django (see Part 1), we now want to add the ability for a user to login, see and copy their token to use, and also refresh their token on an “Account” page.
For this post we’ll skip the user registration / login set up. I typically use a custom user to give more flexibility. This is a good guide to follow on signing up, and registering and authenticating (via email) a custom user.
Create an account page
After you’ve set up your user model and basic views for the web app (i.e. login, logout, register, activate etc.), we can now create an “Account” page.
users/views:
from django.shortcuts import render
from rest_framework.authtoken.models import Token
def account(request):
token, created = Token.objects.get_or_create(user=request.user)
context = {
"token" : token,
"user_email" : request.user.email
}
return render(request, 'users/account.html,context)
This account view is essentially passing through the user’s email and user token to account.html
Next, add the url to urls.py so we can access this view at /account
Let’s create templates/users/account.html to show the token to the user. This page should include some HTML like the following:
<h3> API Key: </h3>
<input
readonly
type="text"
id="tokenText"
value="{{token}}"
/>
<button
data-action="copy"
type="button"
>
Copy
</button>
<h3> Key Created: </h3>
<p id="tokenDate"> {{ token.created|date: "M d Y" }} </p>
This should 1) render our token string, 2) add a button where a user can then copy& then paste their token and also 3) show when the token was generated.
Using some jQuery, we can allow a user to copy their token on the page.
templates/users/account.html:
<script>
$("[data-action='copy']").click(function (e) {
e.preventDefault();
var copyText = document.getElementById("tokenText")
copyText.focus();
copyText.select();
var copied = document.execCommand("copy");
if (copied) {
$(this).removeClass("btn-primary")
.addClass("btn-primary-inverted");
this.innerText = "Copied!";
}
});
</script>
This bit of jQuery uses the document.execCommand("copy")
in order to copy the token value to the user’s clipboard. With Bootstrap, we’re also updating the button UI once copied.
Refreshing Tokens
Once the copy functionality is done, we can now work on adding the ability to refresh a token, triggered by a button click. Let’s add this to our html:
<input
readonly
type="text"
id="tokenText"
value="{{token}}"
/>
<button
data-action="copy"
type="button"
>
Copy
</button>
/// ADD THIS BELOW:
<button
data-action="refresh-token"
type="button"
>
Refresh Key
</button>
<h3> Key Created: </h3>
<p id="tokenDate"> {{ token.created|date: "M d Y" }} </p>
To refresh the token, and return it to our view, we’ll create a new view that will return JSON data to the front-end.
users/views:
from django.shortcuts import render
from rest_framework.authtoken.models import Token
from django.utils.dateformat import format
from django.http import JsonResponse
from django.db import transaction
def refresh_token(request):
old_token = Token.objects.get(user=request.user)
// in order to "refresh" the token,
// we'll delete the old token, then create a new one.
// I prefer to do this in a database transaction,
// that way, the entire transaction will roll-back
// if unsuccessful, and no tokens are deleted.
try:
with transaction.atomic():
old_token.delete()
token, created = Token.objects.get_or_create(user=request.user)
response = {
"new_token": token.key,
"creation_date": format(token.created, "M d Y")
}
except(psycopg2.Error) as e:
response = {
"error": "Unable to refresh key. Please try again."
}
return JsonResponse(response)
Now, our refresh_token
view will return a JSON response of either A) the new token and creation date, or an error. Let’s now update our urls.py:
from django.conf.urls import url
from maddysapi.users import views
urlpatterns = [
url(r'^refresh-token/', views.refresh_token)
]
We can now use this new endpoint on the front end to generate and render a new token using ajax.
If you have your static django paths set up, we can add a new refreshToken.js file. Otherwise, the below can be added to your <script>
in account.html.
static/js/refreshToken.js
window.refreshToken = {
initialize: function () {
var $token = $("#tokenText")
var $generationDate = $("#tokenDate")
$("[data-action='refresh-token']").click(function(e) {
e.preventDefault()
e.stopPropagation()
$.ajax({
method: "GET",
url: "/refresh-token/",
success: function (data) {
if (!data["error"]) {
$token.val(data["new_token"])
$generationDate.text(data["creation_date"])
}
},
error: function(e) {
console.log(e)
}
});
});
}
}
Be sure to add a script tag linking to this js file, to the html page:
templates/users/profile.html:
{% load static %}
<script src="{% static 'js/refreshToken.js' %}" type="text/javascript> </script>
Your ‘Refresh Key’ button should now function as expected — updating the API key and ‘Key Created’ date.
And now your user can view, copy and refresh their API token on their Account page!