一键导入
oidc-hosted-page-android
Implement "Sign in with SSO" in native Android/Kotlin applications using SSOJet OIDC with AppAuth.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Implement "Sign in with SSO" in native Android/Kotlin applications using SSOJet OIDC with AppAuth.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Implement Machine-to-Machine (M2M) authentication using SSOJet OAuth2 Client Credentials flow for backend services and daemons.
Implement "Sign in with SSO" in Angular SPA applications using SSOJet OIDC with PKCE.
Implement "Sign in with SSO" in ASP.NET Core applications using SSOJet OIDC middleware.
Implement "Sign in with SSO" in Go applications using SSOJet OIDC Authorization Code flow.
Implement "Sign in with SSO" in native iOS/Swift applications using SSOJet OIDC with AppAuth.
Implement "Sign in with SSO" in Java Spring Boot applications using SSOJet OIDC with Spring Security.
| name | oidc-hosted-page-android |
| description | Implement "Sign in with SSO" in native Android/Kotlin applications using SSOJet OIDC with AppAuth. |
This expert AI assistant guide walks you through integrating "Sign in with SSO" functionality into an existing Android application using SSOJet as an OIDC identity provider via AppAuth for Android.
net.openid:appauth (AppAuth for Android).com.example.myapp://auth/callback).Note: For native/mobile apps, use Authorization Code with PKCE (no Client Secret on the device).
Add to your app/build.gradle:
// app/build.gradle
dependencies {
implementation 'net.openid:appauth:0.11.1'
}
Add the redirect scheme to your app/build.gradle:
android {
defaultConfig {
manifestPlaceholders = [
'appAuthRedirectScheme': 'com.example.myapp'
]
}
}
Add the redirect activity in AndroidManifest.xml:
<!-- AndroidManifest.xml -->
<activity
android:name="net.openid.appauth.RedirectUriReceiverActivity"
android:exported="true"
tools:node="replace">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="com.example.myapp"
android:host="auth"
android:path="/callback" />
</intent-filter>
</activity>
Create an auth configuration helper (e.g., AuthConfig.kt):
// AuthConfig.kt
package com.example.myapp.auth
import android.net.Uri
import net.openid.appauth.AuthorizationServiceConfiguration
object AuthConfig {
const val CLIENT_ID = "your_client_id"
val REDIRECT_URI: Uri = Uri.parse("com.example.myapp://auth/callback")
val ISSUER_URI: Uri = Uri.parse("https://auth.ssojet.com")
const val SCOPE = "openid profile email"
fun fetchConfiguration(callback: (AuthorizationServiceConfiguration?, Exception?) -> Unit) {
AuthorizationServiceConfiguration.fetchFromIssuer(ISSUER_URI) { config, ex ->
callback(config, ex)
}
}
}
Modify your login activity layout (activity_login.xml):
<!-- res/layout/activity_login.xml -->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="24dp"
android:gravity="center">
<TextView android:text="Sign In"
android:textSize="28sp" android:textStyle="bold"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="24dp" />
<EditText android:id="@+id/emailInput"
android:hint="Email" android:inputType="textEmailAddress"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_marginBottom="16dp" />
<EditText android:id="@+id/passwordInput"
android:hint="Password" android:inputType="textPassword"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_marginBottom="16dp" />
<Button android:id="@+id/signInButton"
android:text="Sign In"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_marginBottom="8dp" />
<Button android:id="@+id/ssoToggleButton"
android:text="Sign in with SSO"
android:background="@android:color/transparent"
android:textColor="#2196F3"
android:layout_width="match_parent" android:layout_height="wrap_content" />
</LinearLayout>
// LoginActivity.kt
package com.example.myapp
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.*
import androidx.activity.result.contract.ActivityResultContracts
import com.example.myapp.auth.AuthConfig
import net.openid.appauth.*
class LoginActivity : Activity() {
private var isSSO = false
private lateinit var authService: AuthorizationService
private val authLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
val data = result.data ?: return@registerForActivityResult
val response = AuthorizationResponse.fromIntent(data)
val exception = AuthorizationException.fromIntent(data)
if (response != null) {
exchangeCodeForToken(response)
} else {
Log.e("OIDC", "Authorization failed: ${exception?.message}")
Toast.makeText(this, "SSO login failed", Toast.LENGTH_SHORT).show()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
authService = AuthorizationService(this)
val emailInput = findViewById<EditText>(R.id.emailInput)
val passwordInput = findViewById<EditText>(R.id.passwordInput)
val signInButton = findViewById<Button>(R.id.signInButton)
val ssoToggle = findViewById<Button>(R.id.ssoToggleButton)
ssoToggle.setOnClickListener {
isSSO = !isSSO
passwordInput.visibility = if (isSSO) View.GONE else View.VISIBLE
signInButton.text = if (isSSO) "Continue with SSO" else "Sign In"
ssoToggle.text = if (isSSO) "Back to Password Login" else "Sign in with SSO"
}
signInButton.setOnClickListener {
val email = emailInput.text.toString()
if (isSSO) {
startSSOLogin(email)
} else {
Log.d("Login", "Processing traditional login...")
}
}
}
private fun startSSOLogin(email: String) {
AuthConfig.fetchConfiguration { config, ex ->
if (config == null) {
Log.e("OIDC", "Discovery failed: ${ex?.message}")
return@fetchConfiguration
}
val authRequest = AuthorizationRequest.Builder(
config,
AuthConfig.CLIENT_ID,
ResponseTypeValues.CODE,
AuthConfig.REDIRECT_URI
)
.setScope(AuthConfig.SCOPE)
.setLoginHint(email)
.build()
val authIntent = authService.getAuthorizationRequestIntent(authRequest)
authLauncher.launch(authIntent)
}
}
private fun exchangeCodeForToken(response: AuthorizationResponse) {
val tokenRequest = response.createTokenExchangeRequest()
authService.performTokenRequest(tokenRequest) { tokenResponse, exception ->
if (tokenResponse != null) {
Log.d("OIDC", "Access Token: ${tokenResponse.accessToken}")
// TODO: Use access token to fetch user info and create session
val intent = Intent(this, DashboardActivity::class.java)
startActivity(intent)
finish()
} else {
Log.e("OIDC", "Token exchange failed: ${exception?.message}")
}
}
}
override fun onDestroy() {
super.onDestroy()
authService.dispose()
}
}
EncryptedSharedPreferences to store tokens securely.