374 Support End Session by smokienko · Pull Request #433 · openid/AppAuth-Android · GitHub
Skip to content

374 Support End Session#433

Closed
smokienko wants to merge 1 commit into
openid:masterfrom
smokienko:end_session_support
Closed

374 Support End Session#433
smokienko wants to merge 1 commit into
openid:masterfrom
smokienko:end_session_support

Conversation

@smokienko

@smokienko smokienko commented Nov 29, 2018

Copy link
Copy Markdown

Implements End Session support flow.
Adds unit tests.
Updates readme.

@codecov-io

codecov-io commented Nov 29, 2018

Copy link
Copy Markdown

@nicholasxmode

Copy link
Copy Markdown

Any idea when this will be available? End Session is an important feature for an auth library...

Comment thread app/build.gradle
// or specify additional redirect URIs in AndroidManifest.xml
manifestPlaceholders = [
'appAuthRedirectScheme': 'net.openid.appauthdemo'
'appAuthRedirectScheme': 'com.lohika.android.test'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be updated before merging to master

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why it hasn't been merged yet?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because there is no maintainer - see #444.

@Barryrowe

Copy link
Copy Markdown

What can we in the community to do support getting this into master for a new release?

@iainmcgin

Copy link
Copy Markdown
Member

Someone needs to step up and take on the role of maintainer - see #444.

@Ju4nD4v1d

Copy link
Copy Markdown

This should be merge already!

@DayS

DayS commented Nov 12, 2019

Copy link
Copy Markdown

Good job 👍

For those looking to use end session support : until a new maintainer is found for this project, you can use a dependency to a binary built from this PR, by using Jitpack (the feature was released yesterday and works like a charm :) )

Juste add the following to your code.

Root build.gradle file :

allprojects {
	repositories {
		...
		maven { url 'https://jitpack.io' }
	}
}

App's build.gradle file :

dependencies {
    implementation 'com.github.openid:AppAuth-Android:PR433-SNAPSHOT'
}

Note that this is not an ideal solution, more a workaround to use this feature.

@MohamedHatemAbdu

Copy link
Copy Markdown

Is there any updates regarding merging this branch into master ?

@rvplauborg

Copy link
Copy Markdown

We too really need this functionality for proper sign-out.

@rvplauborg

rvplauborg commented Feb 24, 2020

Copy link
Copy Markdown

We ended up forking, and using Jitpack to use a dependency built from our own fork with the PR changes, and end session is working for us now without having to do all kinds of workarounds ourselves. Can recommend this approach if you too are in a situation where you cannot just replace your client library with an entirely different one.

@Barryrowe

Copy link
Copy Markdown

For anyone that is still holding out for someone to pick up support of this library, and get this PR merged, but needs to be able to support logging out now without patching in this entire PR (which does. solve it properly), here is the solution we are using:

  1. Extend AuthorizationService with a CustomAuthorizationService
  2. Add and implement fun getLogoutIntent(request: AuthorizationRequest): Intent { //... }
  3. Use request.configuration.toJson() to access the "end_session_endpoint" on your config that is not exposed through the AuthorizationServiceConfiguration class, and build an intent with the resulting URL

Here's our CustomAuthorizationService:

import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.browser.customtabs.CustomTabsIntent
import net.openid.appauth.AppAuthConfiguration
import net.openid.appauth.AuthorizationManagementActivity
import net.openid.appauth.AuthorizationRequest
import net.openid.appauth.AuthorizationService
import net.openid.appauth.internal.Logger
import net.openid.appauth.internal.UriUtil

class CustomAuthorizationService(private val context: Context, private val appAuthConfig: AppAuthConfiguration) : AuthorizationService(context, appAuthConfig) {

    fun getLogoutIntent(
        request: AuthorizationRequest
    ): Intent {

        val logoutIntent = prepareLogoutIntent(request, createCustomTabsIntentBuilder().build())
        return AuthorizationManagementActivity.createStartForResultIntent(
            context,
            request,
            logoutIntent
        )
    }


    /**
     * This is copied directly (and then modified) from {@link net.openid.appauth.AuthorizationService.prepareAuthorizationRequestIntent} since we need
     * to build the same intent, but with the logout destination. Hopefully this can be removed once this PR or similar
     * is merged and released with the AppAuth sdk:
     *    https://github.com/openid/AppAuth-Android/pull/433
     */
    private fun prepareLogoutIntent(
        request: AuthorizationRequest,
        customTabsIntent: CustomTabsIntent
    ): Intent {

        if (browserDescriptor == null) {
            throw ActivityNotFoundException()
        }

        val requestUri = buildLogoutUri(request) // This is where our change comes in. Build Logout instead of authUri
        val intent: Intent = if (browserDescriptor.useCustomTab) {
                customTabsIntent.intent
            } else {
                Intent(Intent.ACTION_VIEW)
            }
        intent.setPackage(browserDescriptor.packageName)
        intent.data = requestUri

        Logger.debug(
            "Using %s as browser for auth, custom tab = %s",
            intent.getPackage(),
            browserDescriptor.useCustomTab.toString()
        )

        Logger.debug(
            "Initiating authorization request to %s",
            request.configuration.authorizationEndpoint
        )

        return intent
    }


    /**
     * The block below was lifted from {@link net.openid.appauth.AuthorizationRequest} since we need to build a proper
     * URI for logout, but it's not possible yet with the current AppAuth library.
     */

    internal val PARAM_CLIENT_ID = "client_id"
    internal val PARAM_CODE_CHALLENGE = "code_challenge"
    internal val PARAM_CODE_CHALLENGE_METHOD = "code_challenge_method"
    internal val PARAM_DISPLAY = "display"
    internal val PARAM_LOGIN_HINT = "login_hint"
    internal val PARAM_ID_TOKEN_HINT = "id_token_hint"
    internal val PARAM_PROMPT = "prompt"
    internal val PARAM_REDIRECT_URI = "redirect_uri"
    internal val PARAM_RESPONSE_MODE = "response_mode"
    internal val PARAM_RESPONSE_TYPE = "response_type"
    internal val PARAM_SCOPE = "scope"
    internal val PARAM_STATE = "state"

    private fun buildLogoutUri(request: AuthorizationRequest): Uri {

        // This is where we rely on the end_session_endpoint being available in the discoveyDoc
        val url = request.configuration.toJson().getJSONObject("discoveryDoc").getString("end_session_endpoint")

        val uriBuilder = Uri.parse(url).buildUpon()
            .appendQueryParameter(PARAM_REDIRECT_URI, request.redirectUri.toString())
            .appendQueryParameter(PARAM_CLIENT_ID, request.clientId)
            .appendQueryParameter(PARAM_RESPONSE_TYPE, request.responseType)

        UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_DISPLAY, request.display)
        UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_LOGIN_HINT, request.loginHint)
        UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_PROMPT, request.prompt)
        UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_STATE, request.state)
        UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_SCOPE, request.scope)
        UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_RESPONSE_MODE, request.responseMode)

        if (request.codeVerifier != null) {
            uriBuilder.appendQueryParameter(PARAM_CODE_CHALLENGE, request.codeVerifierChallenge)
                .appendQueryParameter(PARAM_CODE_CHALLENGE_METHOD, request.codeVerifierChallengeMethod)
        }

        for (entry in request.additionalParameters.entries) {
            uriBuilder.appendQueryParameter(entry.key, entry.value)
        }

        return uriBuilder.build()
    }
}

@Eightyplus

Copy link
Copy Markdown

I'm also looking for a logout feature.

@agologan agologan mentioned this pull request Mar 27, 2020
@oahmedazab

Copy link
Copy Markdown

@Barryrowe
can you please explain your solution more when i will call getLogoutIntent

@oahmedazab

Copy link
Copy Markdown

@Barryrowe
can you please explain your solution more when i will call getLogoutIntent

Thanks man i got it

@Barryrowe

Copy link
Copy Markdown

@oahmedazab Glad you found it helpful!

For anyone else, you would use getLogoutIntent just like you do getAuthorizationRequestIntent for logging in, just during your app's Logout flow.

I did forget to note explicitly, for anyone else, that the above implementation expects using configuration discovery, where the logout endpoint is returned as part of the remote discoveryDoc. The first line of buildLogoutUri() has a comment where you could provide your logout endpoint if you are not using config discovery.

@mshuf

mshuf commented Apr 20, 2020

Copy link
Copy Markdown

@oahmedazab Glad you found it helpful!

For anyone else, you would use getLogoutIntent just like you do getAuthorizationRequestIntent for logging in, just during your app's Logout flow.

I did forget to note explicitly, for anyone else, that the above implementation expects using configuration discovery, where the logout endpoint is returned as part of the remote discoveryDoc. The first line of buildLogoutUri() has a comment where you could provide your logout endpoint if you are not using config discovery.

Thanks @Barryrowe, your comments helped me ending a session in Xamarin.Android until this is merged into master.

@Pavel-Sulimau

Pavel-Sulimau commented Apr 20, 2020

Copy link
Copy Markdown

@oahmedazab Glad you found it helpful!
For anyone else, you would use getLogoutIntent just like you do getAuthorizationRequestIntent for logging in, just during your app's Logout flow.
I did forget to note explicitly, for anyone else, that the above implementation expects using configuration discovery, where the logout endpoint is returned as part of the remote discoveryDoc. The first line of buildLogoutUri() has a comment where you could provide your logout endpoint if you are not using config discovery.

Thanks @Barryrowe, your comments helped me ending a session in Xamarin.Android until this is merged into master.

Hey @mshuf, could you please share your Xamarin.Android solution for the issue?

@mshuf

mshuf commented Apr 21, 2020

Copy link
Copy Markdown
var endsessionEndpointURI = Uri.Parse(string.Format("{0}?id_token_hint={1}&post_logout_redirect_uri={2}", yourBaseURL + "connect/endsession", userIdToken, yourCallBackURI));

var intentBuilder = _authService.CreateCustomTabsIntentBuilder(endsessionEndpointURI);
var customTabsIntent = intentBuilder.Build();
customTabsIntent.Intent.AddFlags(ActivityFlags.SingleTop);
customTabsIntent.Intent.SetData(endsessionEndpointURI);

Intent logoutIntent = AuthorizationManagementActivity.CreateStartForResultIntent(MainActivity.Instance, _authRequest, customTabsIntent.Intent);
MainActivity.Instance.StartActivity(logoutIntent);

@Pavel-Sulimau This is basically what I'm rolling with for now... It launches the end session URI in a custom tab and subsequently logs the user out. From there the user clicks a button which re-directs back to the app where I handle and then display the login screen again. You can have it automatically redirect depending on your auth server setup. Hope this helps.

@Eightyplus

Copy link
Copy Markdown

Nice solution, add id_token_hint and post_logout_redirect_uri to be redirected after successful logout! 🚀

    fun endSession(
        startActivityForResult: StartActivityForResult,
        redirectLogoutUrl: String,
        idToken: String,
        authServiceConfiguration: AuthorizationServiceConfiguration
    ) {

        val endSessionEndpoint = authServiceConfiguration.toJson().getJSONObject("discoveryDoc")
            .getString("end_session_endpoint")
        val reqParam = "id_token_hint=$idToken&post_logout_redirect_uri=${redirectLogoutUrl}"

        val uri = Uri.parse("$endSessionEndpoint?$reqParam")
        val intent = if (isPackageInstalled(context, CUSTOM_TAB_PACKAGE_NAME)) {
            val intent = CustomTabsIntent.Builder().setShowTitle(true).build()
            intent.intent.setPackage(CUSTOM_TAB_PACKAGE_NAME)
            intent.intent.data = uri
            intent.intent
        } else {
            Intent(Intent.ACTION_VIEW, uri)
        }
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
        startActivityForResult(intent, REQUEST_CODE_LOG_OUT)
    }

startActivityForResult activity function is parameterized as activity::startActivityForResult

@keyhuihk01

Copy link
Copy Markdown

Conflicting files
library/java/net/openid/appauth/AuthorizationRequest.java

@lsh-silpion

Copy link
Copy Markdown

Any news here? I would need that feature for a Keycloak-Installation

@djdance djdance mentioned this pull request Sep 17, 2020
@kushanshah11

Copy link
Copy Markdown

For anyone that is still holding out for someone to pick up support of this library, and get this PR merged, but needs to be able to support logging out now without patching in this entire PR (which does. solve it properly), here is the solution we are using:

  1. Extend AuthorizationService with a CustomAuthorizationService
  2. Add and implement fun getLogoutIntent(request: AuthorizationRequest): Intent { //... }
  3. Use request.configuration.toJson() to access the "end_session_endpoint" on your config that is not exposed through the AuthorizationServiceConfiguration class, and build an intent with the resulting URL

Here's our CustomAuthorizationService:

import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.browser.customtabs.CustomTabsIntent
import net.openid.appauth.AppAuthConfiguration
import net.openid.appauth.AuthorizationManagementActivity
import net.openid.appauth.AuthorizationRequest
import net.openid.appauth.AuthorizationService
import net.openid.appauth.internal.Logger
import net.openid.appauth.internal.UriUtil

class CustomAuthorizationService(private val context: Context, private val appAuthConfig: AppAuthConfiguration) : AuthorizationService(context, appAuthConfig) {

    fun getLogoutIntent(
        request: AuthorizationRequest
    ): Intent {

        val logoutIntent = prepareLogoutIntent(request, createCustomTabsIntentBuilder().build())
        return AuthorizationManagementActivity.createStartForResultIntent(
            context,
            request,
            logoutIntent
        )
    }


    /**
     * This is copied directly (and then modified) from {@link net.openid.appauth.AuthorizationService.prepareAuthorizationRequestIntent} since we need
     * to build the same intent, but with the logout destination. Hopefully this can be removed once this PR or similar
     * is merged and released with the AppAuth sdk:
     *    https://github.com/openid/AppAuth-Android/pull/433
     */
    private fun prepareLogoutIntent(
        request: AuthorizationRequest,
        customTabsIntent: CustomTabsIntent
    ): Intent {

        if (browserDescriptor == null) {
            throw ActivityNotFoundException()
        }

        val requestUri = buildLogoutUri(request) // This is where our change comes in. Build Logout instead of authUri
        val intent: Intent = if (browserDescriptor.useCustomTab) {
                customTabsIntent.intent
            } else {
                Intent(Intent.ACTION_VIEW)
            }
        intent.setPackage(browserDescriptor.packageName)
        intent.data = requestUri

        Logger.debug(
            "Using %s as browser for auth, custom tab = %s",
            intent.getPackage(),
            browserDescriptor.useCustomTab.toString()
        )

        Logger.debug(
            "Initiating authorization request to %s",
            request.configuration.authorizationEndpoint
        )

        return intent
    }


    /**
     * The block below was lifted from {@link net.openid.appauth.AuthorizationRequest} since we need to build a proper
     * URI for logout, but it's not possible yet with the current AppAuth library.
     */

    internal val PARAM_CLIENT_ID = "client_id"
    internal val PARAM_CODE_CHALLENGE = "code_challenge"
    internal val PARAM_CODE_CHALLENGE_METHOD = "code_challenge_method"
    internal val PARAM_DISPLAY = "display"
    internal val PARAM_LOGIN_HINT = "login_hint"
    internal val PARAM_ID_TOKEN_HINT = "id_token_hint"
    internal val PARAM_PROMPT = "prompt"
    internal val PARAM_REDIRECT_URI = "redirect_uri"
    internal val PARAM_RESPONSE_MODE = "response_mode"
    internal val PARAM_RESPONSE_TYPE = "response_type"
    internal val PARAM_SCOPE = "scope"
    internal val PARAM_STATE = "state"

    private fun buildLogoutUri(request: AuthorizationRequest): Uri {

        // This is where we rely on the end_session_endpoint being available in the discoveyDoc
        val url = request.configuration.toJson().getJSONObject("discoveryDoc").getString("end_session_endpoint")

        val uriBuilder = Uri.parse(url).buildUpon()
            .appendQueryParameter(PARAM_REDIRECT_URI, request.redirectUri.toString())
            .appendQueryParameter(PARAM_CLIENT_ID, request.clientId)
            .appendQueryParameter(PARAM_RESPONSE_TYPE, request.responseType)

        UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_DISPLAY, request.display)
        UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_LOGIN_HINT, request.loginHint)
        UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_PROMPT, request.prompt)
        UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_STATE, request.state)
        UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_SCOPE, request.scope)
        UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_RESPONSE_MODE, request.responseMode)

        if (request.codeVerifier != null) {
            uriBuilder.appendQueryParameter(PARAM_CODE_CHALLENGE, request.codeVerifierChallenge)
                .appendQueryParameter(PARAM_CODE_CHALLENGE_METHOD, request.codeVerifierChallengeMethod)
        }

        for (entry in request.additionalParameters.entries) {
            uriBuilder.appendQueryParameter(entry.key, entry.value)
        }

        return uriBuilder.build()
    }
}

Hi @Barryrowe can you please help me to integrate this?
how can i integrate this in Android Code?

means how to call on Logout and redirect to another activity?

Thanks in advance.

@kushanshah11

Copy link
Copy Markdown

Nice solution, add id_token_hint and post_logout_redirect_uri to be redirected after successful logout!

    fun endSession(
        startActivityForResult: StartActivityForResult,
        redirectLogoutUrl: String,
        idToken: String,
        authServiceConfiguration: AuthorizationServiceConfiguration
    ) {

        val endSessionEndpoint = authServiceConfiguration.toJson().getJSONObject("discoveryDoc")
            .getString("end_session_endpoint")
        val reqParam = "id_token_hint=$idToken&post_logout_redirect_uri=${redirectLogoutUrl}"

        val uri = Uri.parse("$endSessionEndpoint?$reqParam")
        val intent = if (isPackageInstalled(context, CUSTOM_TAB_PACKAGE_NAME)) {
            val intent = CustomTabsIntent.Builder().setShowTitle(true).build()
            intent.intent.setPackage(CUSTOM_TAB_PACKAGE_NAME)
            intent.intent.data = uri
            intent.intent
        } else {
            Intent(Intent.ACTION_VIEW, uri)
        }
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
        startActivityForResult(intent, REQUEST_CODE_LOG_OUT)
    }

startActivityForResult activity function is parameterized as activity::startActivityForResult

Hi @Eightyplus

can you please let me know below code usage?

if (isPackageInstalled(context, CUSTOM_TAB_PACKAGE_NAME)) {
val intent = CustomTabsIntent.Builder().setShowTitle(true).build()
intent.intent.setPackage(CUSTOM_TAB_PACKAGE_NAME)
intent.intent.data = uri
intent.intent
}

What should i pass CUSTOM_TAB_PACKAGE_NAME ?

what should be isPackageInstalled?

@Barryrowe

Copy link
Copy Markdown

@kushanshah11

For anyone else, you would use getLogoutIntent just like you do getAuthorizationRequestIntent for logging in, just during your app's Logout flow.

I did forget to note explicitly, for anyone else, that the above implementation expects using configuration discovery, where the logout endpoint is returned as part of the remote discoveryDoc. The first line of buildLogoutUri() has a comment where you could provide your logout endpoint if you are not using config discovery.

To expand slighlty, you would use the getLogoutIntent() function to build the logout intent, then pass that to startActivityForResult(), and handle the result in onActivityResult(), at which point you can navigate to your desired post-logout activity as you see fit.

You could optionally use authService.performAuthorizationRequest() to automatically go to your desired activity on completed logout.

@Eightyplus

Eightyplus commented Sep 18, 2020

Copy link
Copy Markdown

@kushanshah11 , ah I left out some code.

const pointing at package for chrome
const val CUSTOM_TAB_PACKAGE_NAME = "com.android.chrome"

one way to check if Chrome is installed

    fun isPackageInstalled(context: Context, packageName: String): Boolean {
        return try {
            context.packageManager.getPackageInfo(packageName, 0)
            true
        } catch (e: PackageManager.NameNotFoundException) {
            false
        }
    }

@kushanshah11

Copy link
Copy Markdown

@kushanshah11 , ah I left out some code.

const pointing at package for chrome
const val CUSTOM_TAB_PACKAGE_NAME = "com.android.chrome"

one way to check if Chrome is installed

    fun isPackageInstalled(context: Context, packageName: String): Boolean {
        return try {
            context.packageManager.getPackageInfo(packageName, 0)
            true
        } catch (e: PackageManager.NameNotFoundException) {
            false
        }
    }

HI @Eightyplus I have implemented your code and it works but now i have one issue.
when i perform logout - > logout browser will open
and in onresultactivity i have pt\ut code for redirect to login

now issue is on logout browser remain open and display you are successfully logout and in back of browser Login activity also redirected.

question is how to close browser on logout?

Thanks in advance.

@Eightyplus

Copy link
Copy Markdown

I guess we had the same issue. The server has to configure/enable logout. We use identity server, and have setup like this

PostLogoutRedirectUris = new[] { "com.domain.myapp:/logout" },

Replace com.domain.myapp to match the one you configured for manifestPlaceholders: [ appAuthRedirectScheme = ...

HI @Eightyplus I have implemented your code and it works but now i have one issue.
when i perform logout - > logout browser will open
and in onresultactivity i have pt\ut code for redirect to login

now issue is on logout browser remain open and display you are successfully logout and in back of browser Login activity also redirected.

question is how to close browser on logout?

Thanks in advance.

@kushanshah11

Copy link
Copy Markdown

@kushanshah11

For anyone else, you would use getLogoutIntent just like you do getAuthorizationRequestIntent for logging in, just during your app's Logout flow.

I did forget to note explicitly, for anyone else, that the above implementation expects using configuration discovery, where the logout endpoint is returned as part of the remote discoveryDoc. The first line of buildLogoutUri() has a comment where you could provide your logout endpoint if you are not using config discovery.

To expand slighlty, you would use the getLogoutIntent() function to build the logout intent, then pass that to startActivityForResult(), and handle the result in onActivityResult(), at which point you can navigate to your desired post-logout activity as you see fit.

You could optionally use authService.performAuthorizationRequest() to automatically go to your desired activity on completed logout.

Hi @Barryrowe ,
i have also implemented your solution and it works but how to close logout webview?

can you please let me know solution for close logout browser?

thanks in advance.

@kushanshah11

Copy link
Copy Markdown

I guess we had the same issue. The server has to configure/enable logout. We use identity server, and have setup like this

PostLogoutRedirectUris = new[] { "com.domain.myapp:/logout" },

Replace com.domain.myapp to match the one you configured for manifestPlaceholders: [ appAuthRedirectScheme = ...

HI @Eightyplus I have implemented your code and it works but now i have one issue.
when i perform logout - > logout browser will open
and in onresultactivity i have pt\ut code for redirect to login
now issue is on logout browser remain open and display you are successfully logout and in back of browser Login activity also redirected.
question is how to close browser on logout?
Thanks in advance.

so based on my understanding first server guy have to add postlogoutredirecturi in discovery document right?

after that what is our part or its automatically close?

Thanks in advance

@Eightyplus

Copy link
Copy Markdown

If you use custom tab / chrome, it will close and redirect. If it runs on an old device with older browser, probably not, but will redirect to your app.

so based on my understanding first server guy have to add postlogoutredirecturi in discovery document right?

after that what is our part or its automatically close?

Thanks in advance

@kushanshah11

Copy link
Copy Markdown

If you use custom tab / chrome, it will close and redirect. If it runs on an old device with older browser, probably not, but will redirect to your app.

so based on my understanding first server guy have to add postlogoutredirecturi in discovery document right?
after that what is our part or its automatically close?
Thanks in advance

yes by default it use chrome. so once server guy added that endpoint in discovery it will automatically works correct ?

@Barryrowe

Copy link
Copy Markdown

@kushanshah11

For anyone else, you would use getLogoutIntent just like you do getAuthorizationRequestIntent for logging in, just during your app's Logout flow.

I did forget to note explicitly, for anyone else, that the above implementation expects using configuration discovery, where the logout endpoint is returned as part of the remote discoveryDoc. The first line of buildLogoutUri() has a comment where you could provide your logout endpoint if you are not using config discovery.

To expand slighlty, you would use the getLogoutIntent() function to build the logout intent, then pass that to startActivityForResult(), and handle the result in onActivityResult(), at which point you can navigate to your desired post-logout activity as you see fit.
You could optionally use authService.performAuthorizationRequest() to automatically go to your desired activity on completed logout.

Hi @Barryrowe ,
i have also implemented your solution and it works but how to close logout webview?

can you please let me know solution for close logout browser?

thanks in advance.

@kushanshah11 There are several pieces to understand about how the redirect works. There are a few different things that could be going on if you're not properly getting redirected to your app after the logout action occurs.

The relevant documentation is in the root of this project here: https://github.com/openid/AppAuth-Android#capturing-the-authorization-redirect

  1. Your app must have a registered URI scheme to handle login/logout redirects.
  2. Your oauth server should redirect to a url that matches that scheme for both actions, likely with an extra path or query param to differentiate login vs logout
  3. You need to add that redirect url for the actions when building the authoriaztion intents. If you use the discovery document, you can pull it from there, but if your oAuth server doesn't provide the discovery document, you can provide it directly however you see fit as a string.

If you're not getting redirected with all the proper setup, make sure you're on API 21 or higher. I believe API 16-19 has some flaky handling of the login flows if you're using startActivityForResult

@danijelt

danijelt commented Sep 23, 2020

Copy link
Copy Markdown

@Barryrowe Something is not clear from your patch, how do you send the id_token_hint parameter (that is being sent by the code in this pull request)? Actually, under what OIDC standard/draft does your logout code work? What IdP do you work with?

@Barryrowe

Copy link
Copy Markdown

@danijelt This is a good question. Our identity provider is Identity Server 4

I was fumbling my way through patching this when I originally wrote this, and left out that detail. That unused PARAM_ID_TOKEN_HINT was added before realizing I don't have access to the AuthState inside the intent builder function. It looks like I'm adding id_token_hint and the post_logout_redirect_uri params when building the AutorizationRequest to pass into getLogoutIntent() using the setAdditionalParameters function.

So given a valid AuthState, and the normal client configuration items (clientId/RedirectUri/scope), my Request Building looks like:

val redirectUri = Uri.parse(redirectUrl)
val authRequest = AuthorizationRequest.Builder(
        state.authorizationServiceConfiguration!!,
        clientId,
        ResponseTypeValues.CODE,
        redirectUri
    )
    .setScope(scope)
    .setAdditionalParameters(
        mapOf(
            LOGOUT_PARAM_ID_TOKEN_HINT to state.idToken,
            LOGOUT_PARAM_POST_LOGOUT_REDIRECT to "$redirectUrl/logout"
        )
    )
    .build()

val intent = (authService as CustomAuthorizationService).getLogoutIntent(authRequest)

@danijelt

Copy link
Copy Markdown

@Barryrowe Thanks for clearing it up! So, the ID token is being sent implicitly with setAdditionalParameters? That's what confused me and I thought you went out-of-spec.

@Barryrowe

Copy link
Copy Markdown

@danijelt The buildLogoutUri function does this at the very end of the function. This is also done in the AuthorizationRequest.toUri() function, which is where I copied the uri building logic from.

https://github.com/openid/AppAuth-Android/blob/master/library/java/net/openid/appauth/AuthorizationRequest.java#L1003

My solution has always been a patch, so it's a little ugly. I'm hoping this PR, or a similar one will get merged and released eventually.

@agologan

Copy link
Copy Markdown
Collaborator

Thanks to @smokienko for the original PR. His changes have been updated and merged as part of #525

@agologan agologan closed this Jan 13, 2021
@dsuresh-ap dsuresh-ap mentioned this pull request Feb 8, 2021
@MonikaMoon

Copy link
Copy Markdown

I am following the code above for end session, I have tried with demo code of TokenActivity.endSession() as well but still unable to end session on my device.

My final url looks like:
httpsBaseURL/end_session?id_token_hint="idToken"&post_logout_redirect_uri=httpsBaseURL/logout

but its giving me error as follows:
"The resource you are looking for has been removed, had its name changed, or is temporarily unavailable."

I am not sure why I am unable to end session properly.

@Barryrowe

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.