Tiny OAuth 2.0 client library in Kotlin that supports JetBrains Hub authorization features.
In the most cases to enable authorization via OAuth 2.0 server you have to know
Client ID and Client Secret that you get when you register your application at the
OAuth 2.0 server. During the registration you often provide a Redirect URI to the OAuth 2.0 server.
This URI is actually a URI in your application that handles responses from the OAuth 2.0 server.
To perform operations authorized by the OAuth 2.0 server, your application requires an Access Token. There
are several ways (so called flows) for your applications to get it. The flow you will use depends on the
environment your application runs in.
repositories {
jcenter()
maven { url "https://jitpack.io" }
}
dependencies {
compile 'com.github.mazine:oauth2-client-kotlin:$version'
}<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories><dependency>
<groupId>com.github.mazine</groupId>
<artifactId>oauth2-client-kotlin</artifactId>
<version>$version</version>
</dependency>
Use it if
- Your application is running on a web server.
- Your application builds HTML responses on the server side.
- The
Client ID,Client Secretand any access token issued to your application are stored on the web server and are not accessible by the end-user.
How It Works?
- User tries to access your application via browser and your application finds out that it doesn't have yet an
Access Tokenfor the user. - Your application saves the information about the URI, user tried to access, under the unique identifier
state. - Your application redirects the user to the OAuth 2.0 server passing the
stateas one of the parameters. - User identifies herself at the OAuth 2.0 server (e.g. by entering her username and password).
- OAuth 2.0 server redirects the user back to your application (to the
Redirect URIto be precise) with two query parameters:stateandcode. - Your application makes a server to server HTTP call to the OAuth 2.0 server exchanging the
codefor theAccess Token. To identify itself your application passes with the call itsClient IDandClient Secret. - Your application using the
staterestores the URI originally requested by the user, and redirects her there.
For further details check OAuth 2.0 Spec or Hub Docs.
The library actually helps to build the URI to redirect the user on the step 3, and to exchange the code for
the Access Token on the step 6.
Build URI
val targetURI = oauth2Client().codeFlowURI(
authEndpoint = URI("https://hub.jetbrains.com/api/rest/oauth2/auth"),
clientID = "1234-3213-3123",
redirectURI = URI("https://localhost:8080/auth"),
scope = listOf("0-0-0-0-0", clientID),
state = "some-unique-state-id")
Exchange code
val accessToken = oauth2Client().codeFlow(
tokenEndpoint = URI("https://hub.jetbrains.com/api/rest/oauth2/token"),
code = "sOMec0de",
redirectURI = URI("https://localhost:8080/auth"),
clientID = "1234-3213-3123",
clientSecret = "sGUl4x")
do {
// Make various calls using accessToken.header
} while (!accessToken.isExpired)
Use it if
- Your application accesses resources on behalf of itself.
- The
Client ID,Client Secretand any access token issued to your application are stored confident.
For further details check OAuth 2.0 Spec or Hub Docs.
The library allows to create an AccessTokenSource for this flow. It is an object that retrieves and
caches an Access Token, and renews the Access Token when it expires.
val tokenSource = oauth2Client().clientFlow(
tokenEndpoint = URI("https://hub.jetbrains.com/api/rest/oauth2/token"),
clientID = "1234-3213-3123",
clientSecret = "sGUl4x",
scope = listOf("0-0-0-0-0", clientID))
do {
// Make various calls using tokenSource.accessToken.header
} while (true)
Use it if
Your application knows user credentials and accesses resources on behalf of a user. For example, your application is the device operating system or a highly privileged application.
For further details check OAuth 2.0 Spec or Hub Docs.
The library allows to create an AccessTokenSource for this flow.
val tokenSource = oauth2Client().resourceOwnerFlow(
tokenEndpoint = URI("https://hub.jetbrains.com/api/rest/oauth2/token"),
username = "john.doe",
password = "p@$Sw0rd",
clientID = "1234-3213-3123",
clientSecret = "sGUl4x",
scope = listOf("0-0-0-0-0", clientID))
do {
// Make various calls using tokenSource.accessToken.header
} while (true)
Use it if
Your application is public. Typically a JavaScript code in a browser.
How It Works?
- User downloads your JavaScript application into her browser. To access resources via REST API your application
needs an
Access Token. - Your application finds out that it has no
Access Tokenyet. - Your application saves the information about the URI, user tried to access, under the unique identifier
state(e.g. in a local storage of the browser). - Your application redirects the user to the OAuth 2.0 server passing the
stateas one of the parameters. - User identifies herself at the OAuth 2.0 server (e.g. by entering her username and password).
- OAuth 2.0 server redirects the user back to your application (to the
Redirect URIto be precise) with anAccess Tokenin parameters after ‘#’. The trick here is that browser sends nothing after ‘#’ in URL to the server, but the part after ‘#’ is accessible for your JavaScript application. So theAccess Tokennever leaves user's browser.
For further details check OAuth 2.0 Spec or Hub Docs.
The library only helps to build the URI to redirect the user on the step 4.
val targetURI = oauth2Client().implicitFlowURI(
authEndpoint = URI("https://hub.jetbrains.com/api/rest/oauth2/auth"),
clientID = "1234-3213-3123",
redirectURI = URI("https://localhost:8080/auth"),
scope = listOf("0-0-0-0-0", clientID),
state = "some-unique-state-id")
Use it if
Your application is a desktop or mobile application that wants to access resources on behalf of user, when the user is offline.
For further details check OAuth 2.0 Spec or Hub Docs.
Your application can obtain a Refresh Token as a part of code or resource owner
flows.
Obtain Refresh Token from code flow
When redirect to OAuth 2.0 server, request refreshToken
oauth2Client().codeFlowURI(
authEndpoint = URI("https://hub.jetbrains.com/api/rest/oauth2/auth"),
clientID = "1234-3213-3123",
redirectURI = URI("https://localhost:8080/auth"),
scope = listOf("0-0-0-0-0", clientID),
state = "some-unique-state-id",
requestRefreshToken = true)
When user returns with a code, use the code to obtain refresh token
val refreshToken = oauth2Client().codeRefreshToken(
tokenEndpoint = URI("https://hub.jetbrains.com/api/rest/oauth2/token"),
code = "sOMec0de",
redirectURI = URI("https://localhost:8080/auth"),
clientID = "1234-3213-3123",
clientSecret = "sGUl4x")
Obtain Refresh Token from resource owner flow
val refreshToken = oauth2Client().resourceOwnerRefreshToken(
tokenEndpoint = URI("https://hub.jetbrains.com/api/rest/oauth2/token"),
username = "john.doe",
password = "p@$Sw0rd",
clientID = "1234-3213-3123",
clientSecret = "sGUl4x",
scope = listOf("0-0-0-0-0", clientID))
Use Refresh Token to get AccessTokenSource
val tokenSource = oauth2Client().refreshTokenFlow(
tokenEndpoint = URI("https://hub.jetbrains.com/api/rest/oauth2/token"),
refreshToken = "that-refresh-token",
clientID = "1234-3213-3123",
clientSecret = "sGUl4x",
scope = listOf("0-0-0-0-0", clientID))
do {
// Make various calls using tokenSource.accessToken.header
} while (true)