Decode base64Url in Java
Asked Answered
H

12

52

https://web.archive.org/web/20110422225659/https://en.wikipedia.org/wiki/Base64#URL_applications

talks about base64Url - Decode


a modified Base64 for URL variant exists, where no padding '=' will be used, and the '+' and '/' characters of standard Base64 are respectively replaced by '-' and '_'


I created the following function:

public static String base64UrlDecode(String input) {
    String result = null;
    BASE64Decoder decoder = new BASE64Decoder();
    try {
        result = decoder.decodeBuffer(input.replace('-','+').replace('/','_')).toString();
    }
    catch (IOException e) {
        System.out.println(e.getMessage());
    }
    return result;
}

it returns a very small set of characters that don't even resemble to the expected results. any ideas?

Hasidism answered 12/4, 2011 at 20:32 Comment(5)
You shouldn't use sun.misc.BASE64Decoder because it is internal Sun/Oracle code (not part of J2SE) and may disappear at any time. The class Base64 in Apache Commons should provide you with all the functionality you need.Salsala
my question is how to properly decode a base64url string in java. and thanks i'll try apache commonsHasidism
@Benjamin, wow, I didn't realize BASE64Decoder was a Sun class, internal or otherwise. I wonder why they broke with their own naming convention. +1Arris
@BenjaminMuschko Might be nice to clarify that is it specifically in Apache Commons Codec for those that don't realise it is a link in your comment! :)Epiphora
Shouldn't it be replace('_','/')Maximomaximum
H
26

With the usage of Base64 from Apache Commons, who can be configured to URL safe, I created the following function:

import org.apache.commons.codec.binary.Base64;

public static String base64UrlDecode(String input) {
    String result = null;
    Base64 decoder = new Base64(true);
    byte[] decodedBytes = decoder.decode(input);
    result = new String(decodedBytes);
    return result;
}

The constructor Base64(true) makes the decoding URL-safe.

Hasidism answered 12/4, 2011 at 21:23 Comment(1)
idle curiosity, why make it that verbose if you could just do this? return new String(new Base64(true).decode(input));Flute
W
90

Java8+

import java.util.Base64;


return Base64.getUrlEncoder().encodeToString(bytes);
Waddle answered 9/7, 2016 at 22:54 Comment(3)
If you don't like trailing '=' (padding), then use: Base64.getUrlEncoder().withoutPadding().encodeToString(str.g‌​etBytes(UTF_8))Mensa
@kiedysktos do you have an example sequence? Table The "URL and Filename safe" Base 64 Alphabet in does not allow / in RFC 4648 which getUrlEncoder() usesWaddle
EDIT: OK, I was using getEncoder() instead of getUrlEncoder(), my faultMacrae
A
52

Base64 encoding is part of the JDK since Java 8. URL safe encoding is also supported with java.util.Base64.getUrlEncoder(), and the "=" padding can be skipped by additionally using the java.util.Base64.Encoder.withoutPadding() method:

import java.nio.charset.StandardCharsets;
import java.util.Base64;

public String encode(String raw) {
    return Base64.getUrlEncoder()
            .withoutPadding()
            .encodeToString(raw.getBytes(StandardCharsets.UTF_8));
}
Anaptyxis answered 27/3, 2015 at 9:29 Comment(2)
The resulting string still contains equal signs. That's not URL safe, is it?Brachycephalic
Use Base64.getUrlEncoder().withoutPadding().encodeToString(str.getBytes(UTF_8))Mensa
H
26

With the usage of Base64 from Apache Commons, who can be configured to URL safe, I created the following function:

import org.apache.commons.codec.binary.Base64;

public static String base64UrlDecode(String input) {
    String result = null;
    Base64 decoder = new Base64(true);
    byte[] decodedBytes = decoder.decode(input);
    result = new String(decodedBytes);
    return result;
}

The constructor Base64(true) makes the decoding URL-safe.

Hasidism answered 12/4, 2011 at 21:23 Comment(1)
idle curiosity, why make it that verbose if you could just do this? return new String(new Base64(true).decode(input));Flute
S
8

In the Android SDK, there's a dedicated flag in the Base64 class: Base64.URL_SAFE, use it like so to decode to a String:

import android.util.Base64;
byte[] byteData = Base64.decode(body, Base64.URL_SAFE);
str = new String(byteData, "UTF-8");
Sardinian answered 5/3, 2016 at 11:17 Comment(0)
K
6

Guava now has Base64 decoding built in.

https://google.github.io/guava/releases/17.0/api/docs/com/google/common/io/BaseEncoding.html

Koheleth answered 17/12, 2012 at 19:10 Comment(0)
K
5
public static byte[] encodeUrlSafe(byte[] data) {
    byte[] encode = Base64.encode(data);
    for (int i = 0; i < encode.length; i++) {
        if (encode[i] == '+') {
            encode[i] = '-';
        } else if (encode[i] == '/') {
            encode[i] = '_';
        }
    }
    return encode;
}

public static byte[] decodeUrlSafe(byte[] data) {
    byte[] encode = Arrays.copyOf(data, data.length);
    for (int i = 0; i < encode.length; i++) {
        if (encode[i] == '-') {
            encode[i] = '+';
        } else if (encode[i] == '_') {
            encode[i] = '/';
        }
    }
    return Base64.decode(encode);
}
Kamilah answered 4/3, 2012 at 22:55 Comment(1)
Warning: Trailing = characters get swallowed!Illustrate
A
3

Right off the bat, it looks like your replace() is backwards; that method replaces the occurrences of the first character with the second, not the other way around.

Arris answered 12/4, 2011 at 20:39 Comment(0)
B
2

@ufk's answer works, but you don't actually need to set the urlSafe flag when you're just decoding.

urlSafe is only applied to encode operations. Decoding seamlessly handles both modes.

Also, there are some static helpers to make it shorter and more explicit:

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;

public static String base64UrlDecode(String input) {
  StringUtils.newStringUtf8(Base64.decodeBase64(input));
}

Docs

Betancourt answered 4/11, 2013 at 19:41 Comment(0)
S
1

This class can help:

import android.util.Base64;

public class Encryptor {

    public static String encode(String input) {
        return Base64.encodeToString(input.getBytes(), Base64.URL_SAFE);
    }

    public static String decode(String encoded) {
        return new String(Base64.decode(encoded.getBytes(), Base64.URL_SAFE));
    }
}
Slavonic answered 24/1, 2019 at 17:27 Comment(0)
S
1

I know the answer is already there, but still, if someone wants...

import java.util.Base64; 

public class Base64BasicEncryptionExample {  

    public static void main(String[] args) {  

       // Getting encoder  
       Base64.Encoder encoder = Base64.getUrlEncoder();  
       // Encoding URL  
       String eStr = encoder.encodeToString
                               ("http://www.javatpoint.com/javatutorial/".getBytes());  
       System.out.println("Encoded URL: "+eStr);  

       // Getting decoder  
       Base64.Decoder decoder = Base64.getUrlDecoder();  
       // Decoding URl  
       String dStr = new String(decoder.decode(eStr));  
       System.out.println("Decoded URL: "+dStr);  
    }  
}  

Took help from: https://www.javatpoint.com/java-base64-encode-decode

Sullivan answered 17/4, 2021 at 2:24 Comment(0)
U
0

Base64.getUrlEncoder() already using -, _ instead of +, /.

See:

java-1.8.0/src.zip!/java/util/Base64.java

java.util.Base64

    /* Returns a Base64.Encoder that encodes using the URL and Filename safe type 
     * base64 encoding scheme.
     * Returns: A Base64 encoder.
     * */


    public static Encoder getUrlEncoder() {
         return Encoder.RFC4648_URLSAFE;
    }

...

    /*
     * It's the lookup table for "URL and Filename safe Base64" as specified in 
     * Table 2 of the RFC 4648, with the '+' and '/' changed to '-' and '_'. This 
     * table is used when BASE64_URL is specified.
     * */

    private static final char[] toBase64URL = {
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
    };

...

    static final Encoder RFC4648_URLSAFE = new Encoder(true, null, -1, true);


Unhurried answered 22/3, 2023 at 6:57 Comment(0)
B
-1

In Java try the method Base64.encodeBase64URLSafeString() from Commons Codec library for encoding.

Bouldon answered 26/11, 2015 at 14:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.