Skip to content

Instantly share code, notes, and snippets.

Created March 16, 2018 17:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save anonymous/eae594db30c780fa8d2c25fa5b1962ce to your computer and use it in GitHub Desktop.
Save anonymous/eae594db30c780fa8d2c25fa5b1962ce to your computer and use it in GitHub Desktop.
Create or test Firebase tokens (source: http://jsfiddle.net/9kopb/n8cads5v/)
label, button {
display: block;
margin-top: 8px;
}
body > fieldset {
float: left;
min-width: 250px;
margin: 10px;
}
fieldset.collapsible {
overflow: hidden;
position: relative;
border: none;
padding-left: 0;
padding-right: 0;
margin: 0;
}
fieldset.collapsible legend {
text-align: right;
position: absolute;
bottom: 0px;
right: 20px;
}
fieldset.collapsible legend a:after {
content: "+";
}
pre {
padding: 10px;
font-size: 16px;
border-radius: 15px;
background-color: #fafafa;
border: 1px solid #999;
max-width: 95%;
word-wrap: break-word;
white-space: pre-wrap;
word-break: break-all;
}
br {
clear: both;
}
.error {
color: red;
}
<h2>Token Generator</h2>
<p>Create Firebase tokens for use in testing, REST URLs, or just for admiring their beauty. Test them against your Firebase instance.</p>
<fieldset>
<legend>Create a Token</legend>
<form id="createToken">
<label for="secret">secret:</label>
<input type="text" id="secret" />
<label for="uid">uid:</label>
<input type="text" id="uid" value="kato" />
<label for="data">json data:</label>
<textarea id="data" cols=50 rows=6></textarea>
<fieldset class="collapsible active">
<legend><a href="#">more options</a></legend>
<label for="expires">expires:</label>
<input type="text" id="expires" value="+30 days" placeholder="+30 days" /> <a href="#max">max</a>
<label for="notBefore">notBefore:</label>
<input type="text" id="notBefore" value="" placeholder="+0 minutes" />
<label><input id="admin" type="checkbox" /> admin</label>
<label><input id="debug" type="checkbox" /> debug</label>
</fieldset>
<button type="submit">create token</button>
</form>
</fieldset>
<fieldset>
<legend>Read/try a Token</legend>
<form id="testToken">
<label>https://
<input type="text" id="instance" placeholder="instance" />.firebaseio.com</label>
<label for="token">token:</label>
<textarea id="token" cols=50 rows=6></textarea>
<button type="submit">test token</button>
</form>
</fieldset>
<br />
<pre id="log"></pre>
<br />
<div>You can put any value into the json data you want and it will appear as part of the auth variable in security. The following administrative options are submitted as a second argument (try clicking "more options" and adding one):
<ul>
<li><strong>expires</strong>: A timestamp (as number of seconds since epoch) denoting the time after which this token should no longer be valid. There is no way to create a token that never expires, but try the "max" link to achieve something close enough.</li>
<li><strong>notBefore</strong>: A timestamp (as number of seconds since epoch) denoting the time before which this token should be rejected by the server.</li>
<li><strong>admin</strong>: Set to true if you want to disable all security rules for this client.</li>
<li><strong>debug</strong>: Set to true to enable debug output from your Security Rules.</li>
</ul>
</div>
$('#createToken').on('submit', createToken);
$('#testToken').on('submit', testToken);
$('#data').on('keyup change', validateJson);
$('#uid').on('keyup change', setJsonId);
$('#createToken')
.on('submit', createToken)
.find('input,textarea')
.on('keyup change', setCreateButton)
.on('keyup change', logCreateFormat);
$('#testToken')
.on('submit', testToken)
.find('input,textarea')
.on('keyup change', setTestButton);
$('fieldset.collapsible legend a').click(function(e) {
e.preventDefault();
toggleMoreInfo($(this).closest('fieldset'));
});
$('a[href="#max"]').click(function(e) {
e.preventDefault();
$('#expires').val('+9999999 days');
});
toggleMoreInfo($('fieldset.collapsible'));
setCreateButton();
setTestButton();
setJsonId();
logCreateFormat();
function setCreateButton() {
var b = !$('#secret').val();
$('#createToken').find('button').prop('disabled', b);
}
function setTestButton() {
var b = !$('#instance').val() || !$('#token').val();
$('#testToken').find('button').prop('disabled', b);
}
function setJsonId() {
var uid = $('#uid').val();
var out = $('#data').val();
try {
var json = JSON.parse(out || '{}');
json.uid = uid;
out = JSON.stringify(json, null, 2);
} catch (e) {
logErr(e);
}
$('#data').val(out);
}
function validateJson() {
log('');
var data = parseData();
if( data !== false ) {
logCreateFormat();
}
}
function createToken(e) {
e.preventDefault();
var secret = $('#secret').val();
var data = parseData();
if( data !== false ) {
var props = getAdminProps();
var tokGen = new FirebaseTokenGenerator(secret);
var token = tokGen.createToken(data, props);
log(token);
$('#token').val(token);
selectLog();
}
return false;
}
function getAdminProps() {
var exp = parseDate($('#expires').val());
var notBefore = parseDate($('#notBefore').val());
var admin = $('#admin').prop('checked');
var debug = $('#debug').prop('checked');
var out = {};
out.expires = exp||0;
if( notBefore ) out.notBefore = notBefore;
if( admin ) out.admin = admin;
if( debug ) out.debug = debug;
return out;
}
function logCreateFormat() {
var secret = $('#secret').val();
var data = parseData();
if( data === false ) return;
log("new FirebaseTokenGenerator("
+(secret? "'"+secret+"'" : '<ENTER SECRET>')
+")\n.createToken("
+ JSON.stringify(parseData()||{}, null, 2)
+ ", "
+ JSON.stringify(getAdminProps(), null, 2)
+ ')');
}
function parseData() {
try {
return JSON.parse($('#data').val() || '{}');
}
catch(e) {
logErr(e);
return false;
}
}
function testToken(e) {
e.preventDefault();
log('');
var fb = new Firebase('https://' + $('#instance').val() + '.firebaseio.com');
var tok = $('#token').val();
var dat = decodeURIComponent(escape(window.atob(tok.split('.')[1])));
fb.auth(tok, function (err) {
if (err) {
logErr(err + "\n\n" + dat);
} else {
log("Authenticated!\n\n" + dat);
}
});
return false;
}
function log(txt) {
$('pre').removeClass('error').text(txt);
}
function logErr(e) {
$('pre').addClass('error').text(e);
}
function parseDate(v) {
if( !v || v === '0' ) { return 0; }
var m, matches = (v || '').match(/^([+-])(\d+) (\w+)$/);
if (matches) {
m = moment().add((matches[1] === '-'? -1 : 1)*parseInt(matches[2], 10), matches[3]);
} else {
m = moment(v);
}
return m.isValid() ? m.unix() : 0;
}
function selectLog() {
function selectElementContents(el) {
var range = document.createRange();
range.selectNodeContents(el);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
var el = document.getElementById("log");
selectElementContents(el);
}
function toggleMoreInfo($fs) {
if( !$fs.data('origHeight') ) {
$fs.data('origHeight', $fs.height());
$fs.data('minHeight', $fs.find('label').outerHeight() + $fs.find('input').outerHeight()+5);
}
$fs.toggleClass('active');
var h = $fs.data($fs.hasClass('active')? 'origHeight' : 'minHeight');
$fs.animate({height: h});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment