OAuth

note

OAuth - 图1

This help topic is in development and will be updated in the future.

OAuth defines a mechanism for authentication using external providers like Google or Facebook safely. You can read more about OAuth. Ktor has a feature to work with OAuth 1a and 2.0

A simplified OAuth 2.0 workflow:

  • The client is redirected to an authorize URL for the specified provider (Google, Facebook, Twitter, Github…). specifying the clientId and a valid redirection URL.
  • Once the login is correct, the provider generates an auth token using a clientSecret associated with that clientId.
  • Then the client is redirected to a valid, previously agreed upon, application URL with an auth token that is signed with the clientSecret.
  • Ktor’s OAuth feature verifies the token and generates a Principal OAuthAccessTokenResponse.
  • With the auth token, you can request, for example, the user’s email or id depending on the provider.

Example:

1. @Location("/login/{type?}") class login(val type: String = "")

3. val loginProviders = listOf(
4. OAuthServerSettings.OAuth2ServerSettings(
5. name = "github",
6. authorizeUrl = "https://github.com/login/oauth/authorize",
7. accessTokenUrl = "https://github.com/login/oauth/access_token",
8. clientId = "***",
9. clientSecret = "***"
10. )
11. ).associateBy {it.name}

13. install(Authentication) {
14. oauth("gitHubOAuth") {
15. client = HttpClient(Apache)
16. providerLookup = { loginProviders[application.locations.resolve<login>(login::class, this).type] }
17. urlProvider = { url(login(it.name)) }
18. }
19. }

21. routing {
22. authenticate("gitHubOAuth") {
23. location<login>() {
24. param("error") {
25. handle {
26. call.loginFailedPage(call.parameters.getAll("error").orEmpty())
27. }
28. }

30. handle {
31. val principal = call.authentication.principal<OAuthAccessTokenResponse>()
32. if (principal != null) {
33. call.loggedInSuccessResponse(principal)
34. } else {
35. call.loginPage()
36. }
37. }
38. }
39. }
40. }

Depending on the OAuth version, you will get a different Principal

1. sealed class OAuthAccessTokenResponse : Principal {
2. data class OAuth1a(
3. val token: String, val tokenSecret: String,
4. val extraParameters: Parameters = Parameters.Empty
5. ) : OAuthAccessTokenResponse()

7. data class OAuth2(
8. val accessToken: String, val tokenType: String,
9. val expiresIn: Long, val refreshToken: String?,
10. val extraParameters: Parameters = Parameters.Empty
11. ) : OAuthAccessTokenResponse()
12. }

Guide, example and testing