#
Authentication Example In Code
#
Introduction
In the examples below, we demonstrate how to implement the Armada authentication flow in different frameworks and languages. Each example follows a similar structure:
- An install endpoint that receives the
app_id
andxcode
, decrypts thexcode
, and redirects to the Armada verification URL. - A callback endpoint that receives the installation data, validates the
xcode
, and stores theaccess_token
securely.
Remember to adapt these examples to your specific project structure, error handling, and security practices. Also, ensure that you implement proper user authentication and authorization in your application.
Check Xcode Decryption Guide to retrieve the decryptXcode
function easily 👍
#
NodeJS - Express
import express from 'express';
import cache from './cache.js'; // Assuming a cache module (like Redis)
import { decryptXcode } from './utils.js'; // Assuming decryption utility
import authMiddleware from './authMiddleware.js'; // Middleware to authenticate the user
import db from './db.js'; // Database utility
const app = express();
app.use(express.json());
// Step 1: Handle Install URL with Authentication Middleware
app.get('/install', authMiddleware, (req, res) => {
const { app_id, xcode } = req.query;
if (!app_id || !xcode) {
return res.status(400).send('Missing required parameters');
}
if (app_id != process.env.ARMADA_APP_ID) {
return res.status(400).send('Invalid app id');
}
let code;
try {
code = decryptXcode(xcode, process.env.ARMADA_APP_SECRET);
} catch (error) {
return res.status(400).send('Decryption failed');
}
// Store xcode, app_id, and your user info in cache (TTL: 5 minutes = 300 seconds)
cache.set(xcode, {
app_id,
code,
user: req.user // Your authenticated user from middleware
}, 300);
// Redirect to Armada verification
res.redirect(`https://api.armadadelivery.com/integrations/apps/install/verify?xcode=${xcode}&code=${code}`);
});
// Step 2: Handle Callback
app.post('/callback', async (req, res) => {
const { xcode, app_data, user_data, access_token } = req.body;
// Validate xcode exists in cache
const stored = await cache.get(xcode);
if (!stored) {
return res.status(400).send('Invalid xcode');
}
const { user } = stored; // Retrieve your user from cache
// Store access_token securely with the user reference
const armadaUserID = user_data.reference_id;
await db.saveArmadaAppToken(armadaUserID, access_token, user);
// Commit changes
res.status(200).send('OK');
});
export default app;
#
Python - Django
from django.http import HttpResponse, HttpResponseRedirect
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
from django.conf import settings
from .utils import decrypt_xcode
from .models import ArmadaAppToken
from django.core.cache import cache
import json
@require_http_methods(["GET"])
def install(request):
app_id = request.GET.get('app_id')
xcode = request.GET.get('xcode')
if not app_id or not xcode:
return HttpResponse('Missing required parameters', status=400)
if app_id != settings.ARMADA_APP_ID:
return HttpResponse('Invalid app id', status=400)
try:
code = decrypt_xcode(xcode, settings.ARMADA_APP_SECRET)
except Exception:
return HttpResponse('Decryption failed', status=400)
# Store xcode, app_id, and user info in cache (TTL: 5 minutes)
cache.set(xcode, {
'app_id': app_id,
'code': code,
'user': request.user.id # Assuming user authentication
}, timeout=300)
return HttpResponseRedirect(f'https://api.armadadelivery.com/integrations/apps/install/verify?xcode={xcode}&code={code}')
@csrf_exempt
@require_http_methods(["POST"])
def callback(request):
data = json.loads(request.body)
xcode = data.get('xcode')
app_data = data.get('app_data')
user_data = data.get('user_data')
access_token = data.get('access_token')
stored = cache.get(xcode)
if not stored:
return HttpResponse('Invalid xcode', status=400)
user_id = stored['user']
# Store access_token securely with the user reference
armada_user_id = user_data['reference_id']
ArmadaAppToken.objects.create(
armada_user_id=armada_user_id,
access_token=access_token,
user_id=user_id
)
return HttpResponse('OK')
#
PHP - Laravel
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Redirect;
use App\Models\ArmadaAppToken;
use App\Utils\XcodeDecryptor;
class ArmadaAuthController extends Controller
{
public function install(Request $request)
{
$appId = $request->query('app_id');
$xcode = $request->query('xcode');
if (!$appId || !$xcode) {
return response('Missing required parameters', 400);
}
if ($appId != config('armada.app_id')) {
return response('Invalid app id', 400);
}
try {
$code = XcodeDecryptor::decrypt($xcode, config('armada.app_secret'));
} catch (\Exception $e) {
return response('Decryption failed', 400);
}
// Store xcode, app_id, and user info in cache (TTL: 5 minutes)
Cache::put($xcode, [
'app_id' => $appId,
'code' => $code,
'user' => auth()->id() // Assuming user authentication
], 300);
return Redirect::to("https://api.armadadelivery.com/integrations/apps/install/verify?xcode={$xcode}&code={$code}");
}
public function callback(Request $request)
{
$data = $request->json()->all();
$xcode = $data['xcode'];
$appData = $data['app_data'];
$userData = $data['user_data'];
$accessToken = $data['access_token'];
$stored = Cache::get($xcode);
if (!$stored) {
return response('Invalid xcode', 400);
}
$userId = $stored['user'];
// Store access_token securely with the user reference
$armadaUserId = $userData['reference_id'];
ArmadaAppToken::create([
'armada_user_id' => $armadaUserId,
'access_token' => $accessToken,
'user_id' => $userId
]);
return response('OK');
}
}
#
Ruby on Rails
# app/controllers/armada_auth_controller.rb
class ArmadaAuthController < ApplicationController
def install
app_id = params[:app_id]
xcode = params[:xcode]
if app_id.blank? || xcode.blank?
return render plain: 'Missing required parameters', status: :bad_request
end
if app_id != ENV['ARMADA_APP_ID']
return render plain: 'Invalid app id', status: :bad_request
end
begin
code = XcodeDecryptor.decrypt(xcode, ENV['ARMADA_APP_SECRET'])
rescue StandardError
return render plain: 'Decryption failed', status: :bad_request
end
# Store xcode, app_id, and user info in cache (TTL: 5 minutes)
Rails.cache.write(xcode, {
app_id: app_id,
code: code,
user: current_user.id # Assuming user authentication
}, expires_in: 5.minutes)
redirect_to "https://api.armadadelivery.com/integrations/apps/install/verify?xcode=#{xcode}&code=#{code}"
end
def callback
data = JSON.parse(request.body.read)
xcode = data['xcode']
app_data = data['app_data']
user_data = data['user_data']
access_token = data['access_token']
stored = Rails.cache.read(xcode)
return render plain: 'Invalid xcode', status: :bad_request if stored.nil?
user_id = stored[:user]
# Store access_token securely with the user reference
armada_user_id = user_data['reference_id']
ArmadaAppToken.create!(
armada_user_id: armada_user_id,
access_token: access_token,
user_id: user_id
)
render plain: 'OK'
end
end
#
Go - Echo
package main
import (
"encoding/json"
"net/http"
"os"
"time"
"github.com/labstack/echo/v4"
"github.com/go-redis/redis/v8"
)
var (
rdb *redis.Client
)
func main() {
e := echo.New()
rdb = redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
e.GET("/install", handleInstall)
e.POST("/callback", handleCallback)
e.Logger.Fatal(e.Start(":8080"))
}
func handleInstall(c echo.Context) error {
appID := c.QueryParam("app_id")
xcode := c.QueryParam("xcode")
if appID == "" || xcode == "" {
return c.String(http.StatusBadRequest, "Missing required parameters")
}
if appID != os.Getenv("ARMADA_APP_ID") {
return c.String(http.StatusBadRequest, "Invalid app id")
}
code, err := decryptXcode(xcode, os.Getenv("ARMADA_APP_SECRET"))
if err != nil {
return c.String(http.StatusBadRequest, "Decryption failed")
}
// Store xcode, app_id, and user info in cache (TTL: 5 minutes)
err = rdb.Set(c.Request().Context(), xcode, map[string]interface{}{
"app_id": appID,
"code": code,
"user": c.Get("user"), // Assuming user authentication middleware
}, 5*time.Minute).Err()
if err != nil {
return c.String(http.StatusInternalServerError, "Failed to store data")
}
return c.Redirect(http.StatusFound, "https://api.armadadelivery.com/integrations/apps/install/verify?xcode="+xcode+"&code="+code)
}
func handleCallback(c echo.Context) error {
var data struct {
Xcode string `json:"xcode"`
AppData map[string]interface{} `json:"app_data"`
UserData map[string]interface{} `json:"user_data"`
AccessToken string `json:"access_token"`
}
if err := c.Bind(&data); err != nil {
return c.String(http.StatusBadRequest, "Invalid request body")
}
stored, err := rdb.Get(c.Request().Context(), data.Xcode).Result()
if err != nil {
return c.String(http.StatusBadRequest, "Invalid xcode")
}
var storedData map[string]interface{}
if err := json.Unmarshal([]byte(stored), &storedData); err != nil {
return c.String(http.StatusInternalServerError, "Failed to parse stored data")
}
userID := storedData["user"]
// Store access_token securely with the user reference
armadaUserID := data.UserData["reference_id"].(string)
// Implement your database logic here to save the token
// For example: db.SaveArmadaAppToken(armadaUserID, data.AccessToken, userID)
return c.String(http.StatusOK, "OK")
}