Basic Auth to Receive Token in Spring Security

2.5k views Asked by At

I am implementing a RESTful API where the user must authenticate. I want the user to POST their credentials in order to receive a JSON web token (JWT), which is then used for the remainder of the session. I have not found any good sources of information to set this up. In particular, I'm having trouble with the filter. Does anybody have any information or tutorials to help me set this up?

2

There are 2 answers

2
Jigish On BEST ANSWER

Here's a working sample code from Spring Security OAuth github. https://github.com/spring-projects/spring-security-oauth/tree/master/tests/annotation/jwt

You probably don't even need to mess with the filters as shown in the above example. If you've custom needs, please post some sample code.

2
mario On

The people at Stormpath have quite a straightforward solution for achieving Oauth. Please take a look at Using Stormpath for API Authentication.

As a summary, your solution will look like this:

  1. You will use the Stormpath Java SDK to easily delegate all your user-management needs.
  2. When the user presses the login button, your front end will send the credentials securely to your backend-end through its REST API.
    1. By the way, you can also completely delegate the login/register/logout functionality to the Servlet Plugin. Stormpath also supports Google, Facebook, LinkedIn and Github login.
  3. Your backend will then try to authenticate the user against the Stormpath Backend and will return an access token as a result:

    /**
     * Authenticates via username (or email) and password and returns a new access token using the Account's ApiKey
     */
    public String getAccessToken(String usernameOrEmail, String password) {
        ApiKey apiKey = null;
        try {
            AuthenticationRequest request = new UsernamePasswordRequest(usernameOrEmail, password);
            AuthenticationResult result = application.authenticateAccount(request);
            Account account = result.getAccount();
            ApiKeyList apiKeys = account.getApiKeys();
            for (ApiKey ak : apiKeys) {
                apiKey = ak;
                break;
            }
            if (apiKey == null) {
                //this account does not yet have an apiKey
                apiKey = account.createApiKey();
            }
        } catch (ResourceException exception) {
            System.out.println("Authentication Error: " + exception.getMessage());
            throw exception;
        }
    
        return getAccessToken(apiKey);
    }
    
    private String getAccessToken(ApiKey apiKey) {
        HttpRequest request = createOauthAuthenticationRequest(apiKey);
        AccessTokenResult accessTokenResult = (AccessTokenResult) application.authenticateApiRequest(request);
        return accessTokenResult.getTokenResponse().getAccessToken();
    }
    
    
    private HttpRequest createOauthAuthenticationRequest(ApiKey apiKey) {
        try {
            String credentials = apiKey.getId() + ":" + apiKey.getSecret();
    
            Map<String, String[]> headers = new LinkedHashMap<String, String[]>();
            headers.put("Accept", new String[]{"application/json"});
            headers.put("Content-Type", new String[]{"application/x-www-form-urlencoded"});
            headers.put("Authorization", new String[]{"Basic " + Base64.encodeBase64String(credentials.getBytes("UTF-8"))});
    
            Map<String, String[]> parameters = new LinkedHashMap<String, String[]>();
            parameters.put("grant_type", new String[]{"client_credentials"});
    
            HttpRequest request = HttpRequests.method(HttpMethod.POST)
                    .headers(headers)
                    .parameters(parameters)
                    .build();
            return request;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
  4. Then, for every authenticated request, your backend will do:

    /** This is your protected API */
    public void sayHello(String accessToken) throws OauthAuthenticationException {
        try {
            if (verify(accessToken)) {
                doStartEngines(); //Here you will actually call your internal doStartEngines() operation
            }
        } catch (OauthAuthenticationException e) {
            System.out.print("[Server-side] Engines not started. accessToken could not be verified: " + e.getMessage());
            throw e;
        }
    }
    
    private boolean verify(String accessToken) throws OauthAuthenticationException {
        HttpRequest request = createRequestForOauth2AuthenticatedOperation(accessToken);
        OauthAuthenticationResult result = application.authenticateOauthRequest(request).execute();
        System.out.println(result.getAccount().getEmail() + " was successfully verified");
        return true;
    }
    
    private HttpRequest createRequestForOauth2AuthenticatedOperation(String token) {
        try {
            Map<String, String[]> headers = new LinkedHashMap<String, String[]>();
            headers.put("Accept", new String[]{"application/json"});
            headers.put("Authorization", new String[]{"Bearer " + token});
            HttpRequest request = HttpRequests.method(HttpMethod.GET)
                    .headers(headers)
                    .build();
            return request;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    

All this will not need any special Spring Security configuration, this is plain Java code that you can run in any framework.

Please take a look here for more information.

Hope that helps!

Disclaimer, I am an active Stormpath contributor.