This Harbour project demonstrates the process of creating and validating a JSON Web Token (JWT).
The workflow involves initializing the necessary variables, creating the payload, encoding the payload into a JWT, and then validating the JWT.
If the JWT is valid, the payload is displayed; otherwise, an error message is shown.
Best regards,
Otto
Explanation of the program:
Initialization:
The program initializes by setting the secret key (cSecret) and the payload (hPayload), which contains information such as the
issued time (iat),
expiration time (exp),
issuer (iss), audience (aud),
resource (resource), and
user data (data).
Payload Creation:
The payload (hPayload) is prepared with the necessary details.
JWT Creation:
The jwtEncode function is called to create a JWT (JSON Web Token) using the payload and the secret key. This function encodes the header and payload in base64 URL format, then creates a signature using HMAC SHA-256 and encodes it in base64 URL format.
JWT Display:
The generated JWT is displayed and logged.
JWT Validation:
The jwtDecode function is called to validate the JWT using the secret key. This function decodes the JWT, verifies the signature, and if valid, converts the payload from JSON to a hash table.
Check Validity:
If the JWT is valid, the payload is displayed and logged. If not, an "Invalid JWT" message is logged.
End:
The process ends after displaying or logging the payload or the error message.
- Code: Select all Expand view RUN
#include "fivewin.ch"
FUNCTION Main()
LOCAL cSecret
LOCAL hPayload
LOCAL cJwt
LOCAL hDecoded
cSecret := "your_secret_key"
hPayload := { 'iat' => UnixTime(), 'exp' => UnixTime() + 3600, ;
'iss' => 'your_domain.com', 'aud' => 'your_application', ;
'resource' => 'php1', 'data' => { 'username' => 'test' } }
xbrowse(hPayload, "hPayload" )
cJwt := jwtEncode(hPayload, cSecret)
? "JWT Token:", cJwt
hDecoded := jwtDecode(cJwt, cSecret)
IF ValType(hDecoded) == 'H'
xbrowse( hDecoded , "hDecoded")
ELSE
? "Invalid JWT"
ENDIF
RETURN NIL
FUNCTION base64UrlEncode(cData)
LOCAL cEncoded
cEncoded := Base64Encode(cData)
cEncoded := StrTran(cEncoded, "+", "-")
cEncoded := StrTran(cEncoded, "/", "_")
cEncoded := StrTran(cEncoded, "=", "")
RETURN cEncoded
FUNCTION base64UrlDecode(cData)
LOCAL cDataFixed
LOCAL nMod
cDataFixed := StrTran(cData, "-", "+")
cDataFixed := StrTran(cDataFixed, "_", "/")
nMod := Len(cDataFixed) % 4
IF nMod != 0
cDataFixed += Replicate("=", 4 - nMod)
ENDIF
RETURN Base64Decode(cDataFixed)
FUNCTION Base64Encode(cData)
LOCAL cOut := ""
LOCAL nInLen := Len(cData)
LOCAL cIn := cData
LOCAL nOutLen, nIndex, nPad
LOCAL nBits, nValue
// Base64 encoding table
LOCAL cBase64 := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
nOutLen := Int((nInLen + 2) / 3) * 4
cOut := Space(nOutLen)
nIndex := 1
FOR nBits := 1 TO nInLen STEP 3
nValue := Asc(SubStr(cIn, nBits, 1)) * 65536 + ;
IIF(nBits + 1 <= nInLen, Asc(SubStr(cIn, nBits + 1, 1)), 0) * 256 + ;
IIF(nBits + 2 <= nInLen, Asc(SubStr(cIn, nBits + 2, 1)), 0)
SubStr(cOut, nIndex, 1) := SubStr(cBase64, Int(nValue / 262144) + 1, 1)
SubStr(cOut, nIndex + 1, 1) := SubStr(cBase64, Int(Mod(nValue, 262144) / 4096) + 1, 1)
SubStr(cOut, nIndex + 2, 1) := IIF(nBits + 1 <= nInLen, SubStr(cBase64, Int(Mod(nValue, 4096) / 64) + 1, 1), "=")
SubStr(cOut, nIndex + 3, 1) := IIF(nBits + 2 <= nInLen, SubStr(cBase64, Mod(nValue, 64) + 1, 1), "=")
nIndex += 4
NEXT
RETURN cOut
FUNCTION Base64Decode(cData)
LOCAL cOut := ""
LOCAL nInLen := Len(cData)
LOCAL cIn := cData
LOCAL nOutLen, nIndex, nPad
LOCAL nValue, nBits
// Base64 decoding table
LOCAL cBase64 := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
LOCAL aDecode := Array(256, 0)
LOCAL i
FOR i := 1 TO 64
aDecode[Asc(SubStr(cBase64, i, 1))] := i - 1
NEXT
nOutLen := Int((nInLen + 3) / 4) * 3
cOut := Space(nOutLen)
nIndex := 1
FOR nBits := 1 TO nInLen STEP 4
nValue := aDecode[Asc(SubStr(cIn, nBits, 1))] * 262144 + ;
aDecode[Asc(SubStr(cIn, nBits + 1, 1))] * 4096 + ;
IIF(SubStr(cIn, nBits + 2, 1) != "=", aDecode[Asc(SubStr(cIn, nBits + 2, 1))] * 64, 0) + ;
IIF(SubStr(cIn, nBits + 3, 1) != "=", aDecode[Asc(SubStr(cIn, nBits + 3, 1))], 0)
SubStr(cOut, nIndex, 1) := Chr(Int(nValue / 65536))
IF SubStr(cIn, nBits + 2, 1) != "="
SubStr(cOut, nIndex + 1, 1) := Chr(Int(Mod(nValue, 65536) / 256))
ENDIF
IF SubStr(cIn, nBits + 3, 1) != "="
SubStr(cOut, nIndex + 2, 1) := Chr(Mod(nValue, 256))
ENDIF
nIndex += 3
NEXT
RETURN RTrim(cOut)
FUNCTION hb_DateTime()
RETURN Seconds()
FUNCTION UnixTime()
LOCAL dEpoch := Ctod("1970-01-01")
LOCAL dToday := Date()
LOCAL nSeconds
// Berechnung der Anzahl der Sekunden seit Mitternacht
LOCAL cTime := Time()
LOCAL nHours := Val(Left(cTime, 2))
LOCAL nMinutes := Val(SubStr(cTime, 4, 2))
LOCAL nSecondsPart := Val(Right(cTime, 2))
nSeconds := (dToday - dEpoch) * 86400 + nHours * 3600 + nMinutes * 60 + nSecondsPart
RETURN nSeconds
FUNCTION jwtEncode(hPayload, cSecret)
LOCAL hHeader
LOCAL cHeader, cPayload
LOCAL cBase64UrlHeader, cBase64UrlPayload
LOCAL cSignature, cBase64UrlSignature
hHeader := { 'typ' => 'JWT', 'alg' => 'HS256' }
cHeader := hb_JsonEncode(hHeader)
cPayload := hb_JsonEncode(hPayload)
cBase64UrlHeader := base64UrlEncode(cHeader)
cBase64UrlPayload := base64UrlEncode(cPayload)
cSignature := hb_HMAC_SHA256(cBase64UrlHeader + "." + cBase64UrlPayload, cSecret)
cBase64UrlSignature := base64UrlEncode(cSignature)
RETURN cBase64UrlHeader + "." + cBase64UrlPayload + "." + cBase64UrlSignature
FUNCTION jwtDecode(cJwt, cSecret)
LOCAL aParts
LOCAL cHeader, cPayload, cSignature
LOCAL cBase64UrlHeader, cBase64UrlPayload, cBase64UrlSignature
LOCAL cValidSignature
LOCAL hDecoded
aParts := hb_ATokens(cJwt, ".")
IF Len(aParts) != 3
RETURN NIL
ENDIF
cHeader := aParts[1]
cPayload := aParts[2]
cSignature := aParts[3]
cBase64UrlHeader := base64UrlEncode(base64UrlDecode(cHeader))
cBase64UrlPayload := base64UrlEncode(base64UrlDecode(cPayload))
cBase64UrlSignature := base64UrlEncode(base64UrlDecode(cSignature))
cValidSignature := base64UrlEncode(hb_HMAC_SHA256(cBase64UrlHeader + "." + cBase64UrlPayload, cSecret))
IF cBase64UrlSignature == cValidSignature
hDecoded := jsonToHash(base64UrlDecode(cPayload))
RETURN hDecoded
ELSE
RETURN NIL
ENDIF
RETURN NIL
FUNCTION jsonToHash(cJson)
LOCAL hResult := {=>} // Initialisierung als leeres Hash-Array
LOCAL cKey, cValue, nPos, nEnd, cSubJson
LOCAL cJsonTrimmed := Trim(cJson)
LOCAL nLen := Len(cJsonTrimmed)
LOCAL cChar
LOCAL lIsArray := .F.
IF Left(cJsonTrimmed, 1) == "[" .AND. Right(cJsonTrimmed, 1) == "]"
cJsonTrimmed := SubStr(cJsonTrimmed, 2, nLen - 2)
lIsArray := .T.
ELSEIF Left(cJsonTrimmed, 1) == "{" .AND. Right(cJsonTrimmed, 1) == "}"
cJsonTrimmed := SubStr(cJsonTrimmed, 2, nLen - 2)
ELSE
RETURN NIL
ENDIF
nPos := 1
WHILE nPos <= Len(cJsonTrimmed)
cChar := SubStr(cJsonTrimmed, nPos, 1)
IF cChar == '"'
nEnd := At('"', cJsonTrimmed, nPos + 1)
cKey := SubStr(cJsonTrimmed, nPos + 1, nEnd - nPos - 1)
nPos := At(":", cJsonTrimmed, nEnd) + 1
nEnd := At(",", cJsonTrimmed, nPos)
IF nEnd == 0
nEnd := Len(cJsonTrimmed) + 1
ENDIF
cValue := Trim(SubStr(cJsonTrimmed, nPos, nEnd - nPos))
IF Left(cValue, 1) == "{" .OR. Left(cValue, 1) == "["
cSubJson := cValue
cValue := jsonToHash(cSubJson)
ELSE
IF ValType(cValue) == "C" .AND. Left(cValue, 1) == '"' .AND. Right(cValue, 1) == '"'
cValue := SubStr(cValue, 2, Len(cValue) - 2)
ELSE
cValue := Val(cValue)
ENDIF
ENDIF
IF lIsArray
AAdd(hResult, cValue)
ELSE
hResult[cKey] := cValue
ENDIF
nPos := nEnd + 1
ELSE
nPos++
ENDIF
ENDDO
RETURN hResult