Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decoding JSON Web Tokens in Swift

trying to decode a JWT payload in Swift and having a really difficult time

static func decodePayload(tokenstr: String) {

    //splitting JWT to extract payload
    let arr = split(tokenstr) {$0 == "."}

    //base64 encoded string i want to decode
    let base64String = arr[1] as String
    println(base64String) //eyJleHAiOjE0MjY4MjIxNjMsImlkIjoiNTUwYjA3NzM4ODk1NjAwZTk5MDAwMDAxIn0

    //attempting to convert base64 string to nsdata 
    let nsdata: NSData = NSData(base64EncodedString: base64String, options: NSDataBase64DecodingOptions(rawValue: 0))

    //decoding fails because nsdata unwraps as nil
    let base64Decoded: NSString = NSString(data: nsdata!, encoding: NSUTF8StringEncoding)!


}
like image 291
andrew nguyen Avatar asked Mar 19 '15 18:03

andrew nguyen


People also ask

Can you decode JWT without secret?

By design, anyone can decode a JWT and read the contents of the header and payload sections. But we need access to the secret key used to create the signature to verify a token's integrity.


2 Answers

eyJleHAiOjE0MjY4MjIxNjMsImlkIjoiNTUwYjA3NzM4ODk1NjAwZTk5MDAwMDAxIn0

is not a valid Base64 encoded string because its length is not a multiple of 4. Some Base64 decoder tolerate this error, but the NSData methods don't.

So this is actually an error on the server side creating the Base64 encoded string. If necessary, you can fix it in your app by adding the required padding with = characters (code updated for Swift 2):

var base64String = arr[1] as String
if base64String.characters.count % 4 != 0 {
    let padlen = 4 - base64String.characters.count % 4
    base64String += String(count: padlen, repeatedValue: Character("="))
}

And now the decoding works as expected:

if let data = NSData(base64EncodedString: base64String, options: []),
    let str = String(data: data, encoding: NSUTF8StringEncoding) {
    print(str) // {"exp":1426822163,"id":"550b07738895600e99000001"}
}

Swift 4:

var base64String = "eyJleHAiOjE0MjY4MjIxNjMsImlkIjoiNTUwYjA3NzM4ODk1NjAwZTk5MDAwMDAxIn0"

if base64String.count % 4 != 0 {
    let padlen = 4 - base64String.count % 4
    base64String.append(contentsOf: repeatElement("=", count: padlen))
}

if let data = Data(base64Encoded: base64String) ,
    let str = String(data: data, encoding: .utf8) {
    print(str) // {"exp":1426822163,"id":"550b07738895600e99000001"}
}
like image 130
Martin R Avatar answered Oct 12 '22 13:10

Martin R


Above solution is working for me, I converted into swift3

Here you can find swift3 code

var base64Str = arr[1] as String
if base64Str.characters.count % 4 != 0 {
    let padlen = 4 - base64Str.characters.count % 4      
    base64Str += String(repeating: "=", count: padlen)
}

if let data = Data(base64Encoded: base64Str, options: []),
    let str = String(data: data, encoding: String.Encoding.utf8) {
        print(str)
}
like image 32
Raju Abe Avatar answered Oct 12 '22 12:10

Raju Abe