Authenticate with pure restful API calls


Is there a way I can authenticate a user with a simple sequence of pure restful calls?

I mean something


if x.Querystring(“result”) = “ok” then
Response.Redirect “Some OKTA URL that came back?
end if

So instead of being stuck in a nightmare of a zillion nuget libraries, we can simply use raw HTTPGET or HTTPPOST or redirects to authenticate a user and then get on with the job of signing them in to the local app.

thanks in advance

Have you taken a look at our /authn API endpoints?

1 Like

I managed to get a pure HTML + javascript version working. I got most of the code from a blog article, but can’t find it now :slight_smile:

<!DOCTYPE html>
    <meta charset="utf-8" />

            <a href="#" id="start">Click to Sign In</a>
            <div id="token">
                <h2>Access Token</h2>
                <div id="access_token"></div>
            <div id="error">
                <div id="error_details"></div>
    <script src="j.js"></script>

// Configure your application and authorization server details
var config = {
    client_id: "xxx",
    redirect_uri: "https://localhost:44336/index.html",
    authorization_endpoint: "",
    token_endpoint: "",
    requested_scopes: "openid"


// Generate a secure random string using the browser crypto functions
function generateRandomString() {
    var array = new Uint32Array(28);
    return Array.from(array, dec => ('0' + dec.toString(16)).substr(-2)).join('');

// Calculate the SHA256 hash of the input text. 
// Returns a promise that resolves to an ArrayBuffer
function sha256(plain) {
    const encoder = new TextEncoder();
    const data = encoder.encode(plain);
    return window.crypto.subtle.digest('SHA-256', data);

// Base64-urlencodes the input string
function base64urlencode(str) {
    // Convert the ArrayBuffer to string using Uint8 array to convert to what btoa accepts.
    // btoa accepts chars only within ascii 0-255 and base64 encodes them.
    // Then convert the base64 encoded to base64url encoded
    //   (replace + with -, replace / with _, trim trailing =)
    return btoa(String.fromCharCode.apply(null, new Uint8Array(str)))
        .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');

// Return the base64-urlencoded sha256 hash for the PKCE challenge
async function pkceChallengeFromVerifier(v) {
    hashed = await sha256(v);
    return base64urlencode(hashed);

// Initiate the PKCE Auth Code flow when the link is clicked
document.getElementById("start").addEventListener("click", async function (e) {

    // Create and store a random "state" value
    var state = generateRandomString();
    localStorage.setItem("pkce_state", state);

    // Create and store a new PKCE code_verifier (the plaintext random secret)
    var code_verifier = generateRandomString();

    localStorage.setItem("pkce_code_verifier", code_verifier);

    // Hash and base64-urlencode the secret to use as the challenge
    var code_challenge = await pkceChallengeFromVerifier(code_verifier);

    // Build the authorization URL
    var url = config.authorization_endpoint
        + "?response_type=code"
        + "&client_id=" + encodeURIComponent(config.client_id)
        + "&state=" + encodeURIComponent(state)
        + "&scope=" + encodeURIComponent(config.requested_scopes)
        + "&redirect_uri=" + encodeURIComponent(config.redirect_uri)
        + "&code_challenge=" + encodeURIComponent(code_challenge)
        + "&code_challenge_method=S256"

    // Redirect to the authorization server
    window.location = url;

// Parse a query string into an object
function parseQueryString(string) {
    if (string == "") { return {}; }
    var segments = string.split("&").map(s => s.split("="));
    var queryString = {};
    segments.forEach(s => queryString[s[0]] = s[1]);
    return queryString;

// Make a POST request and parse the response as JSON
function sendPostRequest(url, params, success, error) {
    var request = new XMLHttpRequest();'POST', url, true);
    request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
    request.onload = function () {
        var body = {};
        try {
            body = JSON.parse(request.response);
        } catch (e) { }

        if (request.status == 200) {
            success(request, body);
        } else {
            error(request, body);
    request.onerror = function () {
        error(request, {});
    var body = Object.keys(params).map(key => key + '=' + params[key]).join('&');

// Handle the redirect back from the authorization server and
// get an access token from the token endpoint

var q = parseQueryString(;

// Check if the server returned an error string
if (q.error) {
    alert("Error returned from authorization server: " + q.error);
    document.getElementById("error_details").innerText = q.error + "\n\n" + q.error_description;

// If the server returned an authorization code, attempt to exchange it for an access token
if (q.code) {

    // Verify state matches what we set at the beginning
    if (localStorage.getItem("pkce_state") != q.state) {
        alert("Invalid state");
    } else {

        // Exchange the authorization code for an access token
        sendPostRequest(config.token_endpoint, {
            grant_type: "authorization_code",
            code: q.code,
            client_id: config.client_id,
            redirect_uri: config.redirect_uri,
            code_verifier: localStorage.getItem("pkce_code_verifier")
        }, function (request, body) {

            // Initialize your application now that you have an access token.
            // Here we just display it in the browser.
            document.getElementById("access_token").innerText = body.access_token;

            // Replace the history entry to remove the auth code from the browser address bar
            window.history.replaceState({}, null, "/");

        }, function (request, error) {
            // This could be an error response from the OAuth server, or an error because the 
            // request failed such as if the OAuth server doesn't allow CORS requests
            document.getElementById("error_details").innerText = error.error + "\n\n" + error.error_description;

    // Clean these up since we don't need them anymore

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.