You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by na...@apache.org on 2015/04/15 21:41:07 UTC

[02/39] jclouds git commit: organized google code into its own subdir

organized google code into its own subdir


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/4da1ba8f
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/4da1ba8f
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/4da1ba8f

Branch: refs/heads/master
Commit: 4da1ba8ff5c3acecf61704b37003114427993da3
Parents: 
Author: Adrian Cole <ad...@gmail.com>
Authored: Sun Apr 28 21:54:40 2013 -0700
Committer: Adrian Cole <ad...@gmail.com>
Committed: Sun Apr 28 22:56:26 2013 -0700

----------------------------------------------------------------------
 apis/oauth/README                               |  22 +++
 apis/oauth/pom.xml                              | 122 ++++++++++++
 .../java/org/jclouds/oauth/v2/OAuthApi.java     |  66 +++++++
 .../org/jclouds/oauth/v2/OAuthApiMetadata.java  |  85 ++++++++
 .../org/jclouds/oauth/v2/OAuthConstants.java    |  78 ++++++++
 .../jclouds/oauth/v2/config/Authentication.java |  38 ++++
 .../v2/config/OAuthAuthenticationModule.java    |  56 ++++++
 .../oauth/v2/config/OAuthHttpApiModule.java     |  49 +++++
 .../jclouds/oauth/v2/config/OAuthModule.java    |  87 +++++++++
 .../oauth/v2/config/OAuthProperties.java        |  48 +++++
 .../jclouds/oauth/v2/config/OAuthScopes.java    |  45 +++++
 .../org/jclouds/oauth/v2/domain/ClaimSet.java   | 194 +++++++++++++++++++
 .../org/jclouds/oauth/v2/domain/Header.java     | 131 +++++++++++++
 .../oauth/v2/domain/OAuthCredentials.java       | 131 +++++++++++++
 .../java/org/jclouds/oauth/v2/domain/Token.java | 153 +++++++++++++++
 .../jclouds/oauth/v2/domain/TokenRequest.java   | 135 +++++++++++++
 .../oauth/v2/domain/TokenRequestFormat.java     |  49 +++++
 .../oauth/v2/filters/OAuthAuthenticator.java    |  67 +++++++
 .../oauth/v2/functions/BuildTokenRequest.java   | 136 +++++++++++++
 .../jclouds/oauth/v2/functions/FetchToken.java  |  47 +++++
 .../v2/functions/OAuthCredentialsSupplier.java  | 127 ++++++++++++
 .../v2/functions/SignOrProduceMacForToken.java  | 123 ++++++++++++
 .../oauth/v2/handlers/OAuthErrorHandler.java    |  68 +++++++
 .../oauth/v2/handlers/OAuthTokenBinder.java     |  49 +++++
 .../oauth/v2/json/ClaimSetTypeAdapter.java      |  63 ++++++
 .../oauth/v2/json/HeaderTypeAdapter.java        |  54 ++++++
 .../oauth/v2/json/JWTTokenRequestFormat.java    | 100 ++++++++++
 .../services/org.jclouds.apis.ApiMetadata       |   1 +
 .../jclouds/oauth/v2/OAuthApiMetadataTest.java  |  42 ++++
 .../org/jclouds/oauth/v2/OAuthTestUtils.java    |  81 ++++++++
 .../oauth/v2/features/OAuthApiExpectTest.java   | 103 ++++++++++
 .../oauth/v2/features/OAuthApiLiveTest.java     |  85 ++++++++
 .../functions/OAuthCredentialsFromPKTest.java   |  60 ++++++
 .../functions/OAuthCredentialsSupplierTest.java |  61 ++++++
 .../oauth/v2/functions/SignerFunctionTest.java  |  65 +++++++
 .../v2/handlers/OAuthErrorHandlerTest.java      |  97 ++++++++++
 .../oauth/v2/internal/Base64UrlSafeTest.java    |  45 +++++
 .../v2/internal/BaseOAuthApiExpectTest.java     |  28 +++
 .../oauth/v2/internal/BaseOAuthApiLiveTest.java |  63 ++++++
 .../BaseOAuthAuthenticatedApiLiveTest.java      | 116 +++++++++++
 .../oauth/v2/internal/BaseOAuthExpectTest.java  |  31 +++
 .../v2/json/JWTTokenRequestFormatTest.java      |  75 +++++++
 .../jclouds/oauth/v2/parse/ParseTokenTest.java  |  46 +++++
 apis/oauth/src/test/resources/logback.xml       |  38 ++++
 apis/oauth/src/test/resources/testpk.pem        |  15 ++
 .../oauth/src/test/resources/tokenResponse.json |   5 +
 46 files changed, 3380 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/README
----------------------------------------------------------------------
diff --git a/apis/oauth/README b/apis/oauth/README
new file mode 100644
index 0000000..32b571a
--- /dev/null
+++ b/apis/oauth/README
@@ -0,0 +1,22 @@
+In order to use oauth applications must specify the following properties:
+
+Mandatory:
+<myprovider>.identity - the oauth identity (e.g., service account email in Google Api's)
+<myprovider>.credential - the private key used to sign requests, in pem format
+oauth.endpoint - the endpoint to use for authentication (e.g., "http://accounts.google.com/o/oauth2/token" in Google Api's)
+oauth.audience - the "audience" of the token request (e.g., "http://accounts.google.com/o/oauth2/token" in Google Api's)
+
+Optional:
+- each application may expose a Map<String,String> of additional claims to be added to the token request,
+these should be annotated/named with "oauth.additional-claims"
+oauth.signature-or-mac-algorithm  - the algorithms to use when signing the token request.
+
+Running the live test:
+
+mvn clean install -Plive\
+ -Dtest.oauth.identity=<accout email>\
+ -Dtest.oauth.credential=<accout pk in pem format>\
+ -Dtest.oauth.endpoint=https://accounts.google.com/o/oauth2/token\
+ -Dtest.jclouds.oauth.audience=https://accounts.google.com/o/oauth2/token\
+ -Dtest.jclouds.oauth.signature-or-mac-algorithm=RS256\
+ -Dtest.jclouds.oauth.scopes=https://www.googleapis.com/auth/prediction
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/pom.xml
----------------------------------------------------------------------
diff --git a/apis/oauth/pom.xml b/apis/oauth/pom.xml
new file mode 100644
index 0000000..aa2cb25
--- /dev/null
+++ b/apis/oauth/pom.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+  Licensed to jclouds, Inc. (jclouds) under one or more
+  contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  jclouds licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.jclouds.labs</groupId>
+        <artifactId>jclouds-labs-google</artifactId>
+        <version>1.7.0-SNAPSHOT</version>
+    </parent>
+
+    <!-- TODO: when out of labs, switch to org.jclouds.api -->
+    <groupId>org.jclouds.labs</groupId>
+    <artifactId>oauth</artifactId>
+    <name>jclouds OAuth core</name>
+    <description>jclouds components to access OAuth</description>
+
+    <properties>
+        <test.oauth.identity>FIX_ME</test.oauth.identity>
+        <test.oauth.credential>FIX_ME</test.oauth.credential>
+        <test.oauth.endpoint>FIX_ME</test.oauth.endpoint>
+        <test.jclouds.oauth.signature-or-mac-algorithm>FIX_ME</test.jclouds.oauth.signature-or-mac-algorithm>
+        <test.jclouds.oauth.audience>FIX_ME</test.jclouds.oauth.audience>
+        <test.jclouds.oauth.scopes>FIX_ME</test.jclouds.oauth.scopes>
+        <test.oauth.api-version>2</test.oauth.api-version>
+        <test.oauth.build-version />
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jclouds</groupId>
+            <artifactId>jclouds-core</artifactId>
+            <version>${jclouds.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jclouds</groupId>
+            <artifactId>jclouds-core</artifactId>
+            <version>${jclouds.version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jclouds.driver</groupId>
+            <artifactId>jclouds-slf4j</artifactId>
+            <version>${jclouds.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-jar-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>live</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>integration</id>
+                                <phase>integration-test</phase>
+                                <goals>
+                                    <goal>test</goal>
+                                </goals>
+                                <configuration>
+                                    <systemPropertyVariables>
+                                        <test.oauth.identity>${test.oauth.identity}</test.oauth.identity>
+                                        <test.oauth.credential>${test.oauth.credential}</test.oauth.credential>
+                                        <test.oauth.endpoint>${test.oauth.endpoint}</test.oauth.endpoint>
+                                        <test.oauth.api-version>${test.oauth.api-version}</test.oauth.api-version>
+                                        <test.oauth.build-version>${test.oauth.build-version}</test.oauth.build-version>
+                                        <test.jclouds.oauth.signature-or-mac-algorithm>${test.jclouds.oauth.signature-or-mac-algorithm&gt;}</test.jclouds.oauth.signature-or-mac-algorithm>
+                                        <test.jclouds.oauth.audience>${test.jclouds.oauth.audience}</test.jclouds.oauth.audience>
+                                        <test.jclouds.oauth.scopes>${test.jclouds.oauth.scopes}</test.jclouds.oauth.scopes>
+                                    </systemPropertyVariables>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java
new file mode 100644
index 0000000..2725778
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.oauth.v2;
+
+import java.io.Closeable;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.oauth.v2.config.Authentication;
+import org.jclouds.oauth.v2.domain.Token;
+import org.jclouds.oauth.v2.domain.TokenRequest;
+import org.jclouds.oauth.v2.handlers.OAuthTokenBinder;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.Endpoint;
+
+/**
+ * Provides access to OAuth via REST api.
+ * <p/>
+ * Usually this is not directly used by a client, which instead specifies
+ * OAuthAuthenticator as a request filter, which in turn uses this class to
+ * perform token requests.
+ * 
+ * @author David Alves
+ * @see OAuthAsyncApi
+ */
+@Endpoint(Authentication.class)
+public interface OAuthApi extends Closeable {
+
+   /**
+    * Authenticates/Authorizes access to a resource defined in TokenRequest
+    * against an OAuth v2 authentication/authorization server.
+    * 
+    * @param tokenRequest
+    *           specified the principal and the required permissions
+    * @return a Token object with the token required to access the resource
+    *         along with its expiration time
+    * @throws AuthorizationException
+    *            if the principal cannot be authenticated or has no permissions
+    *            for the specifed resources.
+    */
+   @Named("authenticate")
+   @POST
+   @Consumes(MediaType.APPLICATION_JSON)
+   Token authenticate(@BinderParam(OAuthTokenBinder.class) TokenRequest tokenRequest) throws AuthorizationException;
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java
new file mode 100644
index 0000000..a093d69
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java
@@ -0,0 +1,85 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.oauth.v2;
+
+import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
+import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.apis.ApiMetadata;
+import org.jclouds.oauth.v2.config.OAuthHttpApiModule;
+import org.jclouds.oauth.v2.config.OAuthModule;
+import org.jclouds.rest.internal.BaseHttpApiMetadata;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+
+/**
+ * Implementation of {@link ApiMetadata} for OAuth 2 API
+ *
+ * @author David Alves
+ */
+public class OAuthApiMetadata extends BaseHttpApiMetadata<OAuthApi> {
+
+   @Override
+   public Builder toBuilder() {
+      return new Builder().fromApiMetadata(this);
+   }
+
+   public OAuthApiMetadata() {
+      this(new Builder());
+   }
+
+   protected OAuthApiMetadata(Builder builder) {
+      super(builder);
+   }
+
+   public static Properties defaultProperties() {
+      Properties properties = BaseHttpApiMetadata.defaultProperties();
+      properties.put(SIGNATURE_OR_MAC_ALGORITHM, "RS256");
+      properties.put(PROPERTY_SESSION_INTERVAL, 3600);
+      return properties;
+   }
+
+   public static class Builder extends BaseHttpApiMetadata.Builder<OAuthApi, Builder> {
+
+      protected Builder() {
+         id("oauth")
+         .name("OAuth API")
+         .identityName("service_account")
+         .credentialName("service_key")
+         .documentation(URI.create("TODO"))
+         .version("2")
+         .defaultProperties(OAuthApiMetadata.defaultProperties())
+         .defaultModules(ImmutableSet.<Class<? extends Module>>of(OAuthModule.class, OAuthHttpApiModule.class));
+      }
+
+      @Override
+      public OAuthApiMetadata build() {
+         return new OAuthApiMetadata(this);
+      }
+
+      @Override
+      protected Builder self() {
+         return this;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java
new file mode 100644
index 0000000..59fc430
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.oauth.v2;
+
+import com.google.common.collect.ImmutableMap;
+
+import java.util.Map;
+
+/**
+ * The constants for OAuth \
+ *
+ * @author David Alves
+ */
+public class OAuthConstants {
+
+   /**
+    * Selected algorithm when a signature or mac isn't required.
+    */
+   public static final String NO_ALGORITHM = "none";
+
+   /**
+    * Static mapping between the oauth algorithm name and the Crypto provider signature algorithm name.
+    *
+    * @see <a href="http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-06#section-3.1">doc</a>
+    * @see org.jclouds.oauth.v2.json.JWTTokenRequestFormat
+    */
+   public static final Map<String, String> OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES = ImmutableMap
+           .<String, String>builder()
+           .put("RS256", "SHA256withRSA")
+           .put("RS384", "SHA384withRSA")
+           .put("RS512", "SHA512withRSA")
+           .put("HS256", "HmacSHA256")
+           .put("HS384", "HmacSHA384")
+           .put("HS512", "HmacSHA512")
+           .put("ES256", "SHA256withECDSA")
+           .put("ES384", "SHA384withECDSA")
+           .put("ES512", "SHA512withECDSA")
+           .put(NO_ALGORITHM, NO_ALGORITHM).build();
+
+   /**
+    * Static mapping between the oauth algorithm name and the Crypto provider KeyFactory algorithm name.
+    *
+    * @see <a href="http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-06#section-3.1">doc</a>
+    */
+   public static final Map<String, String> OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES = ImmutableMap
+           .<String, String>builder()
+           .put("RS256", "RSA")
+           .put("RS384", "RSA")
+           .put("RS512", "RSA")
+           .put("HS256", "DiffieHellman")
+           .put("HS384", "DiffieHellman")
+           .put("HS512", "DiffieHellman")
+           .put("ES256", "EC")
+           .put("ES384", "EC")
+           .put("ES512", "EC")
+           .put(NO_ALGORITHM, NO_ALGORITHM).build();
+
+   /**
+    * The (optional) set of additional claims to use, provided in Map<String,String> form
+    */
+   public static final String ADDITIONAL_CLAIMS = "jclouds.oauth.additional-claims";
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java
new file mode 100644
index 0000000..b0b301d
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java
@@ -0,0 +1,38 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.oauth.v2.config;
+
+
+import javax.inject.Qualifier;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Qualifies OAuth related resources, such as Endpoint.
+ *
+ * @author David Alves
+ * @see org.jclouds.oauth.v2.OAuthAsyncApi
+ */
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
+@Qualifier
+public @interface Authentication {
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java
new file mode 100644
index 0000000..24a5d41
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.oauth.v2.config;
+
+import static org.jclouds.rest.config.BinderUtils.bindHttpApi;
+
+import java.net.URI;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.oauth.v2.OAuthApi;
+
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
+
+/**
+ * An OAuth module to be used form other providers.
+ * 
+ * @author David Alves
+ */
+public class OAuthAuthenticationModule extends AbstractModule {
+
+   @Override
+   protected void configure() {
+      bindHttpApi(binder(), OAuthApi.class);
+   }
+
+   /**
+    * When oauth is used as a module the oauth endpoint is a normal property
+    */
+   @Provides
+   @Singleton
+   @Authentication
+   protected Supplier<URI> provideAuthenticationEndpoint(@Named("oauth.endpoint") String endpoint) {
+      return Suppliers.ofInstance(URI.create(endpoint));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java
new file mode 100644
index 0000000..9234242
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.oauth.v2.config;
+
+import java.net.URI;
+
+import javax.inject.Singleton;
+
+import org.jclouds.oauth.v2.OAuthApi;
+import org.jclouds.providers.ProviderMetadata;
+import org.jclouds.rest.ConfiguresHttpApi;
+import org.jclouds.rest.config.HttpApiModule;
+
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.inject.Provides;
+
+/**
+ * OAuth module to when accessing OAuth stand-alone.
+ * 
+ * @author David Alves
+ */
+@ConfiguresHttpApi
+public class OAuthHttpApiModule extends HttpApiModule<OAuthApi> {
+
+   @Provides
+   @Singleton
+   @Authentication
+   protected Supplier<URI> provideAuthenticationEndpoint(ProviderMetadata providerMetadata) {
+      return Suppliers.ofInstance(URI.create(providerMetadata.getEndpoint()));
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java
new file mode 100644
index 0000000..fc55a87
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.oauth.v2.config;
+
+import com.google.common.base.Function;
+import com.google.common.base.Supplier;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
+import com.google.inject.TypeLiteral;
+import org.jclouds.oauth.v2.domain.ClaimSet;
+import org.jclouds.oauth.v2.domain.Header;
+import org.jclouds.oauth.v2.domain.OAuthCredentials;
+import org.jclouds.oauth.v2.domain.Token;
+import org.jclouds.oauth.v2.domain.TokenRequest;
+import org.jclouds.oauth.v2.functions.BuildTokenRequest;
+import org.jclouds.oauth.v2.functions.FetchToken;
+import org.jclouds.oauth.v2.functions.OAuthCredentialsSupplier;
+import org.jclouds.oauth.v2.functions.SignOrProduceMacForToken;
+import org.jclouds.oauth.v2.json.ClaimSetTypeAdapter;
+import org.jclouds.oauth.v2.json.HeaderTypeAdapter;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+import java.lang.reflect.Type;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
+
+/**
+ * Base OAuth module
+ *
+ * @author David Alves
+ */
+public class OAuthModule extends AbstractModule {
+
+
+   @Override
+   protected void configure() {
+      bind(new TypeLiteral<Function<byte[], byte[]>>() {}).to(SignOrProduceMacForToken.class);
+      bind(new TypeLiteral<Map<Type, Object>>() {}).toInstance(ImmutableMap.<Type, Object>of(
+              Header.class, new HeaderTypeAdapter(),
+              ClaimSet.class, new ClaimSetTypeAdapter()));
+      bind(new TypeLiteral<Supplier<OAuthCredentials>>() {}).to(OAuthCredentialsSupplier.class);
+      bind(new TypeLiteral<Function<GeneratedHttpRequest, TokenRequest>>() {}).to(BuildTokenRequest.class);
+      bind(new TypeLiteral<Function<TokenRequest, Token>>() {}).to(FetchToken.class);
+   }
+
+   /**
+    * Provides a cache for tokens. Cache is time based and expires after 59 minutes (the maximum time a token is
+    * valid is 60 minutes)
+    */
+   @Provides
+   @Singleton
+   public LoadingCache<TokenRequest, Token> provideAccessCache(Function<TokenRequest, Token> getAccess,
+                                                               @Named(PROPERTY_SESSION_INTERVAL) long
+                                                                       sessionIntervalInSeconds) {
+      // since the session interval is also the token expiration time requested to the server make the token expire a
+      // bit before the deadline to make sure there aren't session expiration exceptions
+      sessionIntervalInSeconds = sessionIntervalInSeconds > 30 ? sessionIntervalInSeconds - 30 :
+              sessionIntervalInSeconds;
+      return CacheBuilder.newBuilder().expireAfterWrite(sessionIntervalInSeconds, TimeUnit.MINUTES).build(CacheLoader
+              .from(getAccess));
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java
new file mode 100644
index 0000000..60fb13d
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.oauth.v2.config;
+
+/**
+ * Configurable properties for jclouds OAuth
+ *
+ * @author David Alves
+ */
+public class OAuthProperties {
+
+   /**
+    * The selected signature algorithm to use to sign the requests.
+    * <p/>
+    * This refers to the name the oauth provider expects, i.e., "RSA
+    */
+   public static final String SIGNATURE_OR_MAC_ALGORITHM = "jclouds.oauth.signature-or-mac-algorithm";
+
+   /**
+    * The oauth audience, who this token is intended for. For instance in JWT and for
+    * google API's this property maps to: {"aud","https://accounts.google.com/o/oauth2/token"}
+    *
+    * @see <a href="http://tools.ietf.org/html/draft-jones-json-web-token-04">doc</a>
+    */
+   public static final String AUDIENCE = "jclouds.oauth.audience";
+
+   /**
+    * Optional list of comma-separated scopes to use when no OAuthScopes annotation is present.
+    */
+   public static final String SCOPES = "jclouds.oauth.scopes";
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java
new file mode 100644
index 0000000..f1136fe
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.oauth.v2.config;
+
+import javax.inject.Qualifier;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Used to annotate REST methods/ifaces that use OAuthAuthentication.
+ * <p/>
+ * Sets the scopes for the token request for that particular method.
+ *
+ * @author David Alves
+ */
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target(value = {ElementType.TYPE, ElementType.METHOD})
+@Qualifier
+public @interface OAuthScopes {
+
+   /**
+    * @return the OAuth scopes required to access the resource.
+    */
+   String[] value();
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java
new file mode 100644
index 0000000..998ddcb
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java
@@ -0,0 +1,194 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.oauth.v2.domain;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ForwardingMap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+
+import java.util.Map;
+import java.util.Set;
+
+import static com.google.common.base.Objects.ToStringHelper;
+import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Objects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * The claimset for the token.
+ *
+ * @author David Alves
+ * @see <a
+ *      href="https://developers.google.com/accounts/docs/OAuth2ServiceAccount"
+ *      >doc</a>
+ */
+public class ClaimSet extends ForwardingMap<String, String> {
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return builder().fromClaimSet(this);
+   }
+
+   public static class Builder {
+
+      private Set<String> requiredClaims;
+      private ImmutableMap.Builder<String, String> claims = new ImmutableMap.Builder<String, String>();
+      private long emissionTime;
+      private long expirationTime;
+
+      public Builder() {
+         this(ImmutableSet.<String>of());
+      }
+
+      /**
+       * Constructor that allows to predefine a mandatory set of claims as a comma-separated string, e.g, "iss,iat".
+       */
+      public Builder(String commaSeparatedRequiredClaims) {
+         this(ImmutableSet.copyOf(Splitter.on(",").split(checkNotNull(commaSeparatedRequiredClaims))));
+      }
+
+      /**
+       * Constructor that allows to predefine a mandatory set of claims as a set of strings.
+       */
+      public Builder(Set<String> requiredClaims) {
+         this.requiredClaims = ImmutableSet.copyOf(checkNotNull(requiredClaims));
+      }
+
+      /**
+       * Adds a Claim, i.e. key/value pair, e.g., "scope":"all_permissions".
+       */
+      public Builder addClaim(String name, String value) {
+         claims.put(checkNotNull(name), checkNotNull(value, "value of %s", name));
+         return this;
+      }
+
+      /**
+       * @see ClaimSet#getEmissionTime()
+       */
+      public Builder emissionTime(long emmissionTime) {
+         this.emissionTime = emmissionTime;
+         return this;
+      }
+
+      /**
+       * @see ClaimSet#getExpirationTime()
+       */
+      public Builder expirationTime(long expirationTime) {
+         this.expirationTime = expirationTime;
+         return this;
+      }
+
+      /**
+       * Adds a map containing multiple claims
+       */
+      public Builder addAllClaims(Map<String, String> claims) {
+         this.claims.putAll(checkNotNull(claims));
+         return this;
+      }
+
+      public ClaimSet build() {
+         Map<String, String> claimsMap = claims.build();
+         checkState(Sets.intersection(claimsMap.keySet(), requiredClaims).size() == requiredClaims.size(),
+                 "not all required claims were present");
+         if (expirationTime == 0) {
+            expirationTime = emissionTime + 3600;
+         }
+         return new ClaimSet(claimsMap, emissionTime, expirationTime);
+      }
+
+      public Builder fromClaimSet(ClaimSet claimSet) {
+         return new Builder().addAllClaims(claimSet.claims).expirationTime(expirationTime).emissionTime(emissionTime);
+      }
+   }
+
+   private final Map<String, String> claims;
+   private final long emissionTime;
+   private final long expirationTime;
+
+   private ClaimSet(Map<String, String> claims, long emissionTime, long expirationTime) {
+      this.claims = claims;
+      this.emissionTime = emissionTime;
+      this.expirationTime = expirationTime;
+   }
+
+   /**
+    * The emission time, in seconds since the epoch.
+    */
+   public long getEmissionTime() {
+      return emissionTime;
+   }
+
+   /**
+    * The expiration time, in seconds since the emission time.
+    */
+   public long getExpirationTime() {
+      return expirationTime;
+   }
+
+   /**
+    * @returns the claims.
+    */
+   @Override
+   protected Map<String, String> delegate() {
+      return claims;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(claims);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      ClaimSet other = (ClaimSet) obj;
+      return equal(claims, other.claims);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   protected ToStringHelper string() {
+      return toStringHelper(this).omitNullValues().add("claims", claims)
+              .add("emissionTime", emissionTime).add("expirationTIme", expirationTime);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Header.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Header.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Header.java
new file mode 100644
index 0000000..ab4cd64
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Header.java
@@ -0,0 +1,131 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.oauth.v2.domain;
+
+import com.google.common.base.Objects;
+
+import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Objects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * The header for the OAuth token, contains the signer algorithm's name and the type of the token
+ *
+ * @author David Alves
+ * @see <a href="https://developers.google.com/accounts/docs/OAuth2ServiceAccount">doc</a>
+ */
+public class Header {
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return builder().fromHeader(this);
+   }
+
+   public static class Builder {
+
+      private String signerAlgorithm;
+      private String type;
+
+      /**
+       * @see Header#getSignerAlgorithm()
+       */
+      public Builder signerAlgorithm(String signerAlgorithm) {
+         this.signerAlgorithm = checkNotNull(signerAlgorithm);
+         return this;
+      }
+
+      /**
+       * @see Header#getType()
+       */
+      public Builder type(String type) {
+         this.type = checkNotNull(type);
+         return this;
+      }
+
+      public Header build() {
+         return new Header(signerAlgorithm, type);
+      }
+
+      public Builder fromHeader(Header header) {
+         return new Builder().signerAlgorithm(header.signerAlgorithm).type(header.type);
+      }
+   }
+
+   private final String signerAlgorithm;
+   private final String type;
+
+   protected Header(String signerAlgorithm, String type) {
+      this.signerAlgorithm = checkNotNull(signerAlgorithm);
+      this.type = checkNotNull(type);
+   }
+
+   /**
+    * The name of the algorithm used to compute the signature, e.g., "RS256"
+    */
+   public String getSignerAlgorithm() {
+      return signerAlgorithm;
+   }
+
+   /**
+    * The type of the token, e.g., "JWT"
+    */
+   public String getType() {
+      return type;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      Header other = (Header) obj;
+      return equal(this.signerAlgorithm, other.signerAlgorithm) && equal(this.type,
+              other.type);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(signerAlgorithm, type);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   protected Objects.ToStringHelper string() {
+      return toStringHelper(this).omitNullValues().add("signerAlgorithm", signerAlgorithm)
+              .add("type", type);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java
new file mode 100644
index 0000000..bd2ee25
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java
@@ -0,0 +1,131 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.oauth.v2.domain;
+
+import com.google.common.base.Objects;
+import org.jclouds.domain.Credentials;
+
+import java.security.PrivateKey;
+
+import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Objects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Special kind credentials for oauth authentication that includes {@link java.security.PrivateKey} to sign
+ * requests.
+ */
+public class OAuthCredentials extends Credentials {
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return builder().fromOauthCredentials(this);
+   }
+
+   public static class Builder extends Credentials.Builder<OAuthCredentials> {
+
+      protected PrivateKey privateKey;
+
+      /**
+       * @see OAuthCredentials#privateKey
+       */
+      public Builder privateKey(PrivateKey privateKey) {
+         this.privateKey = checkNotNull(privateKey);
+         return this;
+      }
+
+      /**
+       * @see Credentials#identity
+       */
+      public Builder identity(String identity) {
+         this.identity = checkNotNull(identity);
+         return this;
+      }
+
+      /**
+       * @see Credentials#credential
+       */
+      public Builder credential(String credential) {
+         this.credential = credential;
+         return this;
+      }
+
+      public OAuthCredentials build() {
+         return new OAuthCredentials(checkNotNull(identity), credential, privateKey);
+      }
+
+      public Builder fromOauthCredentials(OAuthCredentials credentials) {
+         return new Builder().privateKey(credentials.privateKey).identity(credentials.identity)
+                 .credential(credentials.credential);
+      }
+   }
+
+   /**
+    * The private key associated with Credentials#identity.
+    * Used to sign token requests.
+    */
+   public final PrivateKey privateKey;
+
+   public OAuthCredentials(String identity, String credential, PrivateKey privateKey) {
+      super(identity, credential);
+      this.privateKey = privateKey;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      OAuthCredentials other = (OAuthCredentials) obj;
+      return equal(this.identity, other.identity) && equal(this.credential,
+              other.credential) && equal(this.privateKey,
+              other.privateKey);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(identity, credential, privateKey);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   protected Objects.ToStringHelper string() {
+      return toStringHelper(this).omitNullValues().add("identity", identity)
+              .add("credential", credential != null ? credential.hashCode() : null).add("privateKey",
+                      privateKey.hashCode());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java
new file mode 100644
index 0000000..6ad47ea
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java
@@ -0,0 +1,153 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.oauth.v2.domain;
+
+import com.google.common.base.Objects;
+
+import java.beans.ConstructorProperties;
+
+import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Objects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * The oauth token, obtained upon a successful token request and ready to embed in requests.
+ *
+ * @author David Alves
+ */
+public class Token {
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return builder().fromToken(this);
+   }
+
+   public static class Builder {
+
+      private String accessToken;
+      private String tokenType;
+      private long expiresIn;
+
+      /**
+       * @see Token#getAccessToken()
+       */
+      public Builder accessToken(String accessToken) {
+         this.accessToken = checkNotNull(accessToken);
+         return this;
+      }
+
+      /**
+       * @see Token#getTokenType()
+       */
+      public Builder tokenType(String tokenType) {
+         this.tokenType = checkNotNull(tokenType);
+         return this;
+      }
+
+      /**
+       * @see Token#getExpiresIn()
+       */
+      public Builder expiresIn(long expiresIn) {
+         this.expiresIn = expiresIn;
+         return this;
+      }
+
+      public Token build() {
+         return new Token(accessToken, tokenType, expiresIn);
+      }
+
+      public Builder fromToken(Token token) {
+         return new Builder().accessToken(token.accessToken).tokenType(token.tokenType).expiresIn(token.expiresIn);
+      }
+   }
+
+   private final String accessToken;
+   private final String tokenType;
+   private final long expiresIn;
+
+   @ConstructorProperties({"access_token", "token_type", "expires_in"})
+   protected Token(String accessToken, String tokenType, long expiresIn) {
+      this.accessToken = accessToken;
+      this.tokenType = tokenType;
+      this.expiresIn = expiresIn;
+   }
+
+   /**
+    * The access token obtained from the OAuth server.
+    */
+   public String getAccessToken() {
+      return accessToken;
+   }
+
+   /**
+    * The type of the token, e.g., "Bearer"
+    */
+   public String getTokenType() {
+      return tokenType;
+   }
+
+   /**
+    * In how many seconds this token expires.
+    */
+   public long getExpiresIn() {
+      return expiresIn;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      Token other = (Token) obj;
+      return equal(this.accessToken, other.accessToken) && equal(this.tokenType,
+              other.tokenType) && equal(this.expiresIn,
+              other.expiresIn);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(accessToken, tokenType, expiresIn);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   protected Objects.ToStringHelper string() {
+      return toStringHelper(this).omitNullValues().add("accessToken", accessToken)
+              .add("tokenType", tokenType).add("expiresIn", expiresIn);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java
new file mode 100644
index 0000000..d2e6ab5
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java
@@ -0,0 +1,135 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.oauth.v2.domain;
+
+import com.google.common.base.Objects;
+
+import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Objects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A complete token request.
+ *
+ * @author David Alves
+ */
+public class TokenRequest {
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return builder().fromTokenRequest(this);
+   }
+
+   public static class Builder {
+      private Header header;
+      private ClaimSet claimSet;
+
+      /**
+       * @see TokenRequest#getClaimSet()
+       */
+      public Builder header(Header header) {
+         this.header = header;
+         return this;
+      }
+
+      /**
+       * @see TokenRequest#getHeader()
+       */
+      public Builder claimSet(ClaimSet claimSet) {
+         this.claimSet = claimSet;
+         return this;
+      }
+
+      public TokenRequest build() {
+         return new TokenRequest(header, claimSet);
+      }
+
+      public Builder fromTokenRequest(TokenRequest tokeRequest) {
+         return new Builder().header(tokeRequest.header).claimSet(tokeRequest.claimSet);
+      }
+   }
+
+   private final Header header;
+   private final ClaimSet claimSet;
+
+   public TokenRequest(Header header, ClaimSet claimSet) {
+      this.header = checkNotNull(header);
+      this.claimSet = checkNotNull(claimSet);
+   }
+
+   /**
+    * The header of this token request.
+    *
+    * @see Header
+    */
+   public Header getHeader() {
+      return header;
+   }
+
+   /**
+    * The claim set of this token request.
+    *
+    * @see ClaimSet
+    */
+   public ClaimSet getClaimSet() {
+      return claimSet;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      TokenRequest other = (TokenRequest) obj;
+      return equal(this.header, other.header) && equal(this.claimSet,
+              other.claimSet);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(header, claimSet);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   protected Objects.ToStringHelper string() {
+      return toStringHelper(this).omitNullValues().add("header", header)
+              .add("claimSet", claimSet);
+   }
+
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java
new file mode 100644
index 0000000..7d4ab63
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.oauth.v2.domain;
+
+import com.google.inject.ImplementedBy;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.oauth.v2.json.JWTTokenRequestFormat;
+
+import java.util.Set;
+
+/**
+ * Transforms a TokenRequest into a specific format (e.g. JWT token)
+ *
+ * @author David Alves
+ */
+@ImplementedBy(JWTTokenRequestFormat.class)
+public interface TokenRequestFormat {
+
+   /**
+    * Transforms the provided HttpRequest into a particular token request with a specific format.
+    */
+   public <R extends HttpRequest> R formatRequest(R httpRequest, TokenRequest tokenRequest);
+
+   /**
+    * The name of the type of the token request, e.g., "JWT"
+    */
+   public String getTypeName();
+
+   /**
+    * The claims that must be present in the token request for it to be valid.
+    */
+   public Set<String> requiredClaims();
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java
new file mode 100644
index 0000000..ccfd2a5
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java
@@ -0,0 +1,67 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.oauth.v2.filters;
+
+import com.google.common.base.Function;
+import com.google.common.cache.LoadingCache;
+import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpRequestFilter;
+import org.jclouds.oauth.v2.domain.Token;
+import org.jclouds.oauth.v2.domain.TokenRequest;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * To be used by client applications to embed an OAuth authentication in their REST requests.
+ * <p/>
+ * TODO when we're able to use the OAuthAuthentication an this should be used automatically
+ *
+ * @author David Alves
+ */
+@Singleton
+public class OAuthAuthenticator implements HttpRequestFilter {
+
+   private Function<GeneratedHttpRequest, TokenRequest> tokenRequestBuilder;
+   private Function<TokenRequest, Token> tokenFetcher;
+
+   @Inject
+   OAuthAuthenticator(Function<GeneratedHttpRequest, TokenRequest> tokenRequestBuilder, LoadingCache<TokenRequest,
+           Token> tokenFetcher) {
+      this.tokenRequestBuilder = tokenRequestBuilder;
+      this.tokenFetcher = tokenFetcher;
+   }
+
+   @Override
+   public HttpRequest filter(HttpRequest request) throws HttpException {
+      checkState(request instanceof GeneratedHttpRequest, "request must be an instance of GeneratedHttpRequest");
+      GeneratedHttpRequest generatedHttpRequest = GeneratedHttpRequest.class.cast(request);
+      TokenRequest tokenRequest = tokenRequestBuilder.apply(generatedHttpRequest);
+      Token token = tokenFetcher.apply(tokenRequest);
+      return request.toBuilder().addHeader("Authorization", String.format("%s %s",
+              token.getTokenType(), token.getAccessToken())).build();
+
+   }
+
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java
new file mode 100644
index 0000000..8faa22d
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.oauth.v2.functions;
+
+import static com.google.common.base.Preconditions.checkState;
+import static org.jclouds.oauth.v2.OAuthConstants.ADDITIONAL_CLAIMS;
+import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE;
+import static org.jclouds.oauth.v2.config.OAuthProperties.SCOPES;
+import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Singleton;
+
+import org.jclouds.Constants;
+import org.jclouds.oauth.v2.config.OAuthScopes;
+import org.jclouds.oauth.v2.domain.ClaimSet;
+import org.jclouds.oauth.v2.domain.Header;
+import org.jclouds.oauth.v2.domain.OAuthCredentials;
+import org.jclouds.oauth.v2.domain.TokenRequest;
+import org.jclouds.oauth.v2.domain.TokenRequestFormat;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Supplier;
+import com.google.common.base.Ticker;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.reflect.Invokable;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+
+/**
+ * The default authenticator.
+ * <p/>
+ * Builds the default token request with the following claims: iss,scope,aud,iat,exp.
+ * <p/>
+ * TODO scopes etc should come from the REST method and not from a global property
+ *
+ * @author David Alves
+ */
+@Singleton
+public class BuildTokenRequest implements Function<GeneratedHttpRequest, TokenRequest> {
+
+   private final String assertionTargetDescription;
+   private final String signatureAlgorithm;
+   private final TokenRequestFormat tokenRequestFormat;
+   private final Supplier<OAuthCredentials> credentialsSupplier;
+   private final long tokenDuration;
+
+   @Inject(optional = true)
+   @Named(ADDITIONAL_CLAIMS)
+   protected Map<String, String> additionalClaims = ImmutableMap.of();
+
+   @Inject(optional = true)
+   @Named(SCOPES)
+   protected String globalScopes = null;
+
+   @Inject(optional = true)
+   public Ticker ticker = Ticker.systemTicker();
+
+
+   @Inject
+   public BuildTokenRequest(@Named(AUDIENCE) String assertionTargetDescription,
+                            @Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureAlgorithm,
+                            TokenRequestFormat tokenRequestFormat, Supplier<OAuthCredentials> credentialsSupplier,
+                            @Named(Constants.PROPERTY_SESSION_INTERVAL) long tokenDuration) {
+      this.assertionTargetDescription = assertionTargetDescription;
+      this.signatureAlgorithm = signatureAlgorithm;
+      this.tokenRequestFormat = tokenRequestFormat;
+      this.credentialsSupplier = credentialsSupplier;
+      this.tokenDuration = tokenDuration;
+   }
+
+   @Override
+   public TokenRequest apply(GeneratedHttpRequest request) {
+      long now = TimeUnit.SECONDS.convert(ticker.read(), TimeUnit.NANOSECONDS);
+
+      // fetch the token
+      Header header = new Header.Builder()
+              .signerAlgorithm(signatureAlgorithm)
+              .type(tokenRequestFormat.getTypeName())
+              .build();
+
+      ClaimSet claimSet = new ClaimSet.Builder(this.tokenRequestFormat.requiredClaims())
+              .addClaim("iss", credentialsSupplier.get().identity)
+              .addClaim("scope", getOAuthScopes(request))
+              .addClaim("aud", assertionTargetDescription)
+              .emissionTime(now)
+              .expirationTime(now + tokenDuration)
+              .addAllClaims(additionalClaims)
+              .build();
+
+      return new TokenRequest.Builder()
+              .header(header)
+              .claimSet(claimSet)
+              .build();
+   }
+
+   protected String getOAuthScopes(GeneratedHttpRequest request) {
+      Invokable<?, ?> invokable = request.getInvocation().getInvokable();
+      
+      OAuthScopes classScopes = invokable.getOwnerType().getRawType().getAnnotation(OAuthScopes.class);
+      OAuthScopes methodScopes = invokable.getAnnotation(OAuthScopes.class);
+
+      // if no annotations are present the rely on globally set scopes
+      if (classScopes == null && methodScopes == null) {
+         checkState(globalScopes != null, String.format("REST class or method should be annotated " +
+                 "with OAuthScopes specifying required permissions. Alternatively a global property " +
+                 "\"oauth.scopes\" may be set to define scopes globally. REST Class: %s, Method: %s",
+                 invokable.getOwnerType(),
+                 invokable.getName()));
+         return globalScopes;
+      }
+
+      OAuthScopes scopes = methodScopes != null ? methodScopes : classScopes;
+      return Joiner.on(",").join(scopes.value());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java
new file mode 100644
index 0000000..a7975d9
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.oauth.v2.functions;
+
+import com.google.common.base.Function;
+import org.jclouds.oauth.v2.OAuthApi;
+import org.jclouds.oauth.v2.domain.Token;
+import org.jclouds.oauth.v2.domain.TokenRequest;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * @author David Alves
+ */
+@Singleton
+public class FetchToken implements Function<TokenRequest, Token> {
+
+   private OAuthApi oAuthApi;
+
+   @Inject
+   public FetchToken(OAuthApi oAuthApi) {
+      this.oAuthApi = oAuthApi;
+   }
+
+   @Override
+   public Token apply(TokenRequest input) {
+      return this.oAuthApi.authenticate(input);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java
new file mode 100644
index 0000000..d74bed5
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java
@@ -0,0 +1,127 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.oauth.v2.functions;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Supplier;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.util.concurrent.UncheckedExecutionException;
+import org.jclouds.domain.Credentials;
+import org.jclouds.location.Provider;
+import org.jclouds.oauth.v2.domain.OAuthCredentials;
+import org.jclouds.rest.AuthorizationException;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Throwables.propagate;
+import static java.lang.String.format;
+import static org.jclouds.crypto.Pems.privateKeySpec;
+import static org.jclouds.io.Payloads.newStringPayload;
+import static org.jclouds.oauth.v2.OAuthConstants.NO_ALGORITHM;
+import static org.jclouds.oauth.v2.OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES;
+import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM;
+import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
+
+/**
+ * Loads {@link OAuthCredentials} from a pem private key using the KeyFactory obtained from the JWT Algorithm
+ * Name<->KeyFactory name mapping in OAuthConstants. The pem pk algorithm must match the KeyFactory algorithm.
+ *
+ * @author David Alves
+ * @see org.jclouds.oauth.v2.OAuthConstants#OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES
+ */
+@Singleton
+public class OAuthCredentialsSupplier implements Supplier<OAuthCredentials> {
+
+   private final Supplier<Credentials> creds;
+   private final LoadingCache<Credentials, OAuthCredentials> keyCache;
+
+   @Inject
+   public OAuthCredentialsSupplier(@Provider Supplier<Credentials> creds, OAuthCredentialsForCredentials loader,
+                                   @Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm) {
+      this.creds = creds;
+      checkArgument(OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES.containsKey(signatureOrMacAlgorithm),
+              format("No mapping for key factory for algorithm: %s", signatureOrMacAlgorithm));
+      // throw out the private key related to old credentials
+      this.keyCache = CacheBuilder.newBuilder().maximumSize(2).build(checkNotNull(loader, "loader"));
+   }
+
+   /**
+    * it is relatively expensive to extract a private key from a PEM. cache the relationship between current credentials
+    * so that the private key is only recalculated once.
+    */
+   @VisibleForTesting
+   static class OAuthCredentialsForCredentials extends CacheLoader<Credentials, OAuthCredentials> {
+      private final String keyFactoryAlgorithm;
+
+      @Inject
+      public OAuthCredentialsForCredentials(@Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm) {
+         this.keyFactoryAlgorithm = OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES.get(checkNotNull(
+                 signatureOrMacAlgorithm, "signatureOrMacAlgorithm"));
+      }
+
+      @Override
+      public OAuthCredentials load(Credentials in) {
+         try {
+            String identity = in.identity;
+            String privateKeyInPemFormat = in.credential;
+            if (keyFactoryAlgorithm.equals(NO_ALGORITHM)) {
+               return new OAuthCredentials.Builder().identity(identity).credential(privateKeyInPemFormat).build();
+            }
+            KeyFactory keyFactory = KeyFactory.getInstance(keyFactoryAlgorithm);
+            PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec(newStringPayload(privateKeyInPemFormat)));
+            return new OAuthCredentials.Builder().identity(identity).credential(privateKeyInPemFormat)
+                    .privateKey(privateKey).build();
+         } catch (IOException e) {
+            throw propagate(e);
+            // catch security exceptions InvalidKeySpecException and NoSuchAlgorithmException as GSE
+         } catch (GeneralSecurityException e) {
+            throw new AuthorizationException("security exception loading credentials. " + e.getMessage(), e);
+            // catch IAE that is thrown when parsing the pk fails
+         } catch (IllegalArgumentException e) {
+            throw new AuthorizationException("cannot parse pk. " + e.getMessage(), e);
+         }
+      }
+   }
+
+   @Override
+   public OAuthCredentials get() {
+      try {
+         // loader always throws UncheckedExecutionException so no point in using get()
+         return keyCache.getUnchecked(checkNotNull(creds.get(), "credential supplier returned null"));
+      } catch (UncheckedExecutionException e) {
+         Throwable authorizationException = getFirstThrowableOfType(e, AuthorizationException.class);
+         if (authorizationException != null) {
+            throw ((AuthorizationException) authorizationException);
+         }
+         throw propagate(e);
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java
new file mode 100644
index 0000000..0d590a8
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.oauth.v2.functions;
+
+import com.google.common.base.Function;
+import com.google.common.base.Supplier;
+import com.google.common.base.Throwables;
+import org.jclouds.oauth.v2.domain.OAuthCredentials;
+
+import javax.annotation.PostConstruct;
+import javax.crypto.Mac;
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.security.SignatureException;
+
+import static com.google.common.base.Preconditions.checkState;
+import static java.lang.String.format;
+import static org.jclouds.oauth.v2.OAuthConstants.NO_ALGORITHM;
+import static org.jclouds.oauth.v2.OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES;
+import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM;
+
+/**
+ * Function that signs/produces mac's for  OAuth tokens, provided a {@link Signature} or a {@link Mac} algorithm and
+ * {@link PrivateKey}
+ *
+ * @author David Alves
+ */
+public class SignOrProduceMacForToken implements Function<byte[], byte[]> {
+
+   private final Supplier<OAuthCredentials> credentials;
+   private final String signatureOrMacAlgorithm;
+   private Function<byte[], byte[]> signatureOrMacFunction;
+
+
+   @Inject
+   public SignOrProduceMacForToken(@Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm,
+                                   Supplier<OAuthCredentials> credentials) {
+      checkState(OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES.containsKey(signatureOrMacAlgorithm),
+              format("the signature algorithm %s is not supported", signatureOrMacAlgorithm));
+      this.signatureOrMacAlgorithm = OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES.get(signatureOrMacAlgorithm);
+      this.credentials = credentials;
+   }
+
+   @PostConstruct
+   public void loadSignatureOrMacOrNone() throws InvalidKeyException, NoSuchAlgorithmException {
+      if (signatureOrMacAlgorithm.equals(NO_ALGORITHM)) {
+         this.signatureOrMacFunction = new Function<byte[], byte[]>() {
+            @Override
+            public byte[] apply(byte[] input) {
+               return null;
+            }
+         };
+      } else if (signatureOrMacAlgorithm.startsWith("SHA")) {
+         this.signatureOrMacFunction = new SignatureGenerator(signatureOrMacAlgorithm, credentials.get().privateKey);
+      } else {
+         this.signatureOrMacFunction = new MessageAuthenticationCodeGenerator(signatureOrMacAlgorithm,
+                 credentials.get().privateKey);
+      }
+   }
+
+   @Override
+   public byte[] apply(byte[] input) {
+      return signatureOrMacFunction.apply(input);
+   }
+
+   private static class MessageAuthenticationCodeGenerator implements Function<byte[], byte[]> {
+
+      private Mac mac;
+
+      private MessageAuthenticationCodeGenerator(String macAlgorithm, PrivateKey privateKey) throws
+              NoSuchAlgorithmException, InvalidKeyException {
+         this.mac = Mac.getInstance(macAlgorithm);
+         this.mac.init(privateKey);
+      }
+
+      @Override
+      public byte[] apply(byte[] input) {
+         this.mac.update(input);
+         return this.mac.doFinal();
+      }
+   }
+
+   private static class SignatureGenerator implements Function<byte[], byte[]> {
+
+      private Signature signature;
+
+      private SignatureGenerator(String signatureAlgorithm, PrivateKey privateKey) throws NoSuchAlgorithmException,
+              InvalidKeyException {
+         this.signature = Signature.getInstance(signatureAlgorithm);
+         this.signature.initSign(privateKey);
+      }
+
+      @Override
+      public byte[] apply(byte[] input) {
+         try {
+            signature.update(input);
+            return signature.sign();
+         } catch (SignatureException e) {
+            throw Throwables.propagate(e);
+         }
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/4da1ba8f/apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java
new file mode 100644
index 0000000..f83c833
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.oauth.v2.handlers;
+
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.ResourceNotFoundException;
+
+import javax.inject.Singleton;
+
+import static javax.ws.rs.core.Response.Status;
+import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
+
+/**
+ * This will parse and set an appropriate exception on the command object.
+ *
+ * @author David Alves
+ */
+@Singleton
+public class OAuthErrorHandler implements HttpErrorHandler {
+   public void handleError(HttpCommand command, HttpResponse response) {
+      // it is important to always read fully and close streams
+      byte[] data = closeClientButKeepContentStream(response);
+      String message = data != null ? new String(data) : null;
+
+      Exception exception = message != null ? new HttpResponseException(command, response, message)
+              : new HttpResponseException(command, response);
+      message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
+              response.getStatusLine());
+      Status status = Status.fromStatusCode(response.getStatusCode());
+      switch (status) {
+         case BAD_REQUEST:
+            break;
+         case UNAUTHORIZED:
+         case FORBIDDEN:
+            exception = new AuthorizationException(message, exception);
+            break;
+         case NOT_FOUND:
+            if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
+               exception = new ResourceNotFoundException(message, exception);
+            }
+            break;
+         case CONFLICT:
+            exception = new IllegalStateException(message, exception);
+            break;
+      }
+      command.setException(exception);
+   }
+}