How to use Amazon Cognito Logout endpoint? - logout

I am using AWS Cognito in my application.
While doing logout i am calling the Logout Endpoint.
But after doing logout, I am still able to generate the id-tokens using the old refresh token.
It means my logout endpoint is not working any more. I am saving the tokens in my local storage, And while doing the logout i am clearing the store manually.
My Question is: How to properly use the logout mechanism of AWS
Cognito?

I'm not sure which framework you are using, but I'm using Angular. Unfortunately there are different ways of using AWS Cognito and the documentation is not clear. Here is my implementation of the Authentication Service (using Angular):
- Note 1 - With using this sign in method - once you redirect the user to the logout url - the localhost refreshes automatically and the token gets deleted.
- Note 2 - You can also do it manually by calling: this.userPool.getCurrentUser().signOut()
import { Injectable } from '#angular/core'
import { CognitoUserPool, ICognitoUserPoolData, CognitoUser } from 'amazon-cognito-identity-js'
import { CognitoAuth } from 'amazon-cognito-auth-js'
import { Router } from '#angular/router'
const COGNITO_CONFIGS: ICognitoUserPoolData = {
UserPoolId: '{INSERT YOUR USER POOL ID}',
ClientId: '{INSERT YOUR CLIENT ID}',
}
#Injectable()
export class CognitoService {
userPool: CognitoUserPool
constructor(
private router: Router
) {
this.createAuth()
}
createAuth(): void {
// Configuration for Auth instance.
const authData = {
UserPoolId: COGNITO_CONFIGS.UserPoolId,
ClientId: COGNITO_CONFIGS.ClientId,
RedirectUriSignIn : '{INSERT YOUR COGNITO REDIRECT URI}',
RedirectUriSignOut : '{INSERT YOUR COGNITO SIGNOUT URI}',
AppWebDomain : '{INSERT YOUR AMAZON COGNITO DOMAIN}',
TokenScopesArray: ['email']
}
const auth: CognitoAuth = new CognitoAuth(authData)
// Callbacks, you must declare, but can be empty.
auth.userhandler = {
onSuccess: function(result) {
},
onFailure: function(err) {
}
}
// Provide the url and parseCognitoWebResponse handles parsing it for us.
const curUrl = window.location.href
auth.parseCognitoWebResponse(curUrl)
}
/**
* Check's if the user is authenticated - used by the Guard.
*/
authenticated(): CognitoUser | null {
this.userPool = new CognitoUserPool(COGNITO_CONFIGS)
// behind the scene getCurrentUser looks for the user on the local storage.
return this.userPool.getCurrentUser()
}
logout(): void {
this.router.navigate(['/logout'])
}
}

Related

Keycloak Capacitor Adapter - Auth Redirect Problem

We are using Ionic Vue (5.4.0 - Vue3) with Capacitor and Keycloak as the Auth Provider. We have implemented the https://www.npmjs.com/package/keycloak-ionic Package which provides the Capacitor Adapter. We have set up the required deeplinks for both platforms and they are working. The app should authenticate the user in the system browser (capacitor-native adapter), save the tokens and reuse these tokens on the next appstart. It's working on android. On iOS the first startup is working but if i restart (terminating and starting again) i only see a blank screen. It's not redirecting into the secured content or showing the keycloak login page. I found out that the Safari Browser with the keycloak login is opened in the background. If i close this browser tab and start the app it's working by redirecting me to the keycloak login page.
May the browser with the opened keycloak instance be the problem?
I also tried the same with inappbrowster (capacitor adapter). The first start is working there also. If i restart the app the custom tab is opening the redirect url page without redirecting me to the secured content or to the keycloak login page.
Code Sample:
App.addListener('appUrlOpen', function (data: any) {
const slug = data.url.split('/kc1').pop()
// We only push to the route if there is a slug present
if (slug) {
router.push({ name: 'Overview' })
}
})
// init authentication
const initKeycloak = async () => {
const cachedKeycloak = new CacheUtil('keycloak')
const cachedKeycloakAccessToken = await cachedKeycloak.get('accessToken')
const cachedKeycloakRefreshToken = await cachedKeycloak.get('refreshToken')
const initOptions = { url: process.env.VUE_APP_AUTH_URL + '/auth', realm: 'mp', clientId: 'mobile', checkLoginIframe: false, onLoad: 'login-required', token: cachedKeycloakAccessToken, refreshToken: cachedKeycloakRefreshToken }
const keycloak = KeycloakIonic(initOptions)
keycloak.init({
adapter: 'capacitor-native',
pkceMethod:'S256',
onLoad: initOptions.onLoad as any,
redirectUri: process.env.VUE_APP_REDIRECT_URI
}).then((auth: any) => {
// auth and create app
if (!auth) {
console.log(auth)
} else {
const app = createApp(VueApp)
.use(IonicVue)
.use(router)
.use(store)
router.isReady().then(() => {
app.mount('#app')
})
}
}).catch((e: Error) => {
console.log('auth failed: ', e)
})
keycloak.onAuthSuccess = () => {
console.log('authenticated!')
// save tokens to device storage
cachedKeycloak.set('accessToken', keycloak.token)
cachedKeycloak.set('refreshToken', keycloak.refreshToken)
}
}
initKeycloak()

Integration AspNet.Security.OpenId.Providers Steam authorization with reactive.js?

I have a ASP.Net Core 2.2 Web API which uses Steam login for authentication using this package.
My authentication looks like this:
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.LoginPath = "/Api/Login";
options.LogoutPath = "/Api/Logout";
})
.AddSteam(opt => { opt.CallbackPath = "/Home/SteamCallback"; opt.ApplicationKey = "XXXX"; });
I'm using this API with my react app and I want to login so I added this in my react project to login
Via Steam
And /api/login redirects user back to react's homepage:
[HttpGet("/api/login")]
public IActionResult Login(string provider="Steam")
{
return Challenge(new AuthenticationProperties { RedirectUri = "http://localhost:3000/" }, provider);
}
I know it's so stupid to try authorize like that but i dont have any idea how.
Also they say using JWT is not safe in here so I had to use cookies but could not handle how to pass logged data to react and fetch data successfully.

How to fetch access token from OAuth used in google action for smart home

For my smart home action I used fake auth as shown in codelab- smartwasher application. (For testing purpose ). The app is working fine. I have build my own code to work with my devices(Switches). Now When I am implementing OAuth which uses my own custom OAuth server. I am not able to figure out how to implement it in my code. The OAuth is working as needed when I tested. But I want help in integrating it with google action. I am facing problem fetching access token.
The code is as follows:
exports.fakeauth = functions.https.onRequest((request, response) => {
const responseurl = util.format('%s?code=%s&state=%s',
decodeURIComponent(request.query.redirect_uri), request.query.code,
request.query.state);
console.log('*********'+responseurl);
return response.redirect(responseurl);
});
exports.faketoken = functions.https.onRequest((request, response) => {
const grantType = request.query.grant_type
? request.query.grant_type : request.body.grant_type;
const secondsInDay = 86400; // 60 * 60 * 24
const HTTP_STATUS_OK = 200;
console.log(`Grant type ${grantType}`);
let obj;
if (grantType === 'authorization_code') {
obj = {
token_type: 'bearer',
access_token: '123access',
refresh_token: '123refresh',
expires_in: secondsInDay,
};
} else if (grantType === 'refresh_token') {
obj = {
token_type: 'bearer',
access_token: '123access',
expires_in: secondsInDay,
};
}
response.status(HTTP_STATUS_OK)
.json(obj);
console.log('********** TOKEN **********',response);
});
The above code executes with fake auth.
Why is is not executing when I am implmenting custom OAuth?
Do I need to do any changes for clienID and secret in firebase?
How to fetch access token returned by OAuth?
Kindly help. I am new to node.js.
The authorization code that will come back in requests will be in the header, as an Authorization field. Here's a way to pull it out using Node.js.
function getToken(headers) {
// Authorization: "Bearer 123ABC"
return headers.authorization.substr(7);
}

Why is IdentityServer redirecting to http rather than https?

I have a very simple MVC5 website that I'm trying to secure with IdentityServer3.
Both my website and my IdentityServer instance are hosted as separate sites in AppHarbor. Both are behind https.
When I hit a resource in my website that is protected by an [Authorize] attribute (e.g., /Home/About), I am successfully redirected to IdentityServer, and I can successfully authenticate.
When IdentityServer POSTs its response back to the website (via app.FormPostResponse.js), the website responds with a 302 redirect to the requested resource - as expected. However, this redirect is to http, not https (see the network trace below).
I'm sure this is just something wrong with my IdentityServer config, but I'd appreciate any pointers as to what I've got wrong.
(AppHarbor uses a reverse proxy (nginx I believe) in front of IIS, where SSL terminates - so I have RequireSsl = false for this scenario, as per the IdentityServer documentation.)
Here is my website's Startup.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "https://<my-idsrv3>.apphb.com/identity",
ClientId = "<my-client-id>",
Scope = "openid profile roles email",
RedirectUri = "https://<my-website>.apphb.com",
ResponseType = "id_token",
SignInAsAuthenticationType = "Cookies",
UseTokenLifetime = false
});
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
}
}
Here is Startup.cs from my IdentityServer3 instance:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/identity", idsrvApp =>
{
idsrvApp.UseIdentityServer(new IdentityServerOptions
{
SiteName = "My Identity Server",
SigningCertificate = Certificates.LoadSigningCertificate(),
RequireSsl = false,
PublicOrigin = "https://<my-idsrv3>.apphb.com",
Factory = new IdentityServerServiceFactory()
.UseInMemoryUsers(Users.Get())
.UseInMemoryClients(Clients.Get())
.UseInMemoryScopes(Scopes.Get())
});
});
}
}
Here is the definition of my website Client:
new Client
{
Enabled = true,
ClientName = "My Website Client",
ClientId = "<my-client-id>",
Flow = Flows.Implicit,
RedirectUris = new List<string>
{
"https://<my-website>.apphb.com"
},
AllowAccessToAllScopes = true
}
Here is the trace from Chrome, after clicking 'Yes, Allow' on the IdentityServer consent screen:
So it looks like this issue was caused by my client website being behind an SSL-terminating nginx front-end.
With reference to this GitHub issue, I added the following to the start of my website's app configuration:
app.Use(async (ctx, next) =>
{
string proto = ctx.Request.Headers.Get("X-Forwarded-Proto");
if (!string.IsNullOrEmpty(proto))
{
ctx.Request.Scheme = proto;
}
await next();
});
This makes the website aware that incoming requests were over https; this in turn appears to ensure that the IdentityServer3 middleware generates https uri's.
Had the same issue running identityserver4 in an Azure App Service. Even with forced https, the generated urls in .well-known/openid-configuration were still http://.
Fixed using the same solution as the other answer, but using AspNetCore ForwardedHeadersExtensions:
var forwardOptions = new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,
// Needed because of mixing http and https.
RequireHeaderSymmetry = false,
};
// Accept X-Forwarded-* headers from all sources.
forwardOptions.KnownNetworks.Clear();
forwardOptions.KnownProxies.Clear();
app.UseForwardedHeaders(forwardOptions);
See also https://github.com/IdentityServer/IdentityServer4/issues/1331 for more discussion on this subject.
Add forwarded headers in your startup
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost;
});
and
app.UseForwardedHeaders(new ForwardedHeadersOptions()
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
Finally tell the config it has to replace the http to https in the redirect url. I'm still looking for a better way to implement this.
in your .addopenidconnect() add:
Func<RedirectContext, Task> redirectToIdentityProvider = (ctx) =>
{
if (!ctx.ProtocolMessage.RedirectUri.StartsWith("https") && !ctx.ProtocolMessage.RedirectUri.Contains("localhost"))
ctx.ProtocolMessage.RedirectUri = ctx.ProtocolMessage.RedirectUri.Replace("http", "https");
return Task.FromResult(0);
};
opt.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = redirectToIdentityProvider
};

Can't receive push notifications using Ionic Cloud on iOS

I'm using ionic's cloud push notification service for both android and iOS, along with phonegap-plugin-push. Since i'm using my own server-side authentcation and not ionic's, I have it configured so that a user's authentication token is registered depending on whether or not they're logged in, and saved when they log in (unregistered when they log out).
App.module:
const cloudSettings: CloudSettings = {
'core': {
'app_id': 'APP_ID',
},
'push': {
'sender_id': 'SENDER_ID',
'pluginConfig': {
'ios': {
'badge': true,
'sound': true,
},
'android': {
'iconColor': '#343434'
}
}
}
};
instead of making push a provider in app module, I made an injectable service that can be used across components. The main app component subscribes to the notifications, while my login and logout components tell it whether or not to register and save them.
export class NotificationService{
token: PushToken;
registered: boolean;
constructor(public push: Push){
}
checkLogin(status){
if(!status){
this.push.register().then((pushT: PushToken) => {
this.token = pushT;
console.log('token saved:'+ this.token);
});
}
}
saveToken(){
this.push.saveToken(this.token);
console.log('token saved');
this.registered = true;
this.startListening();
}
deleteToken(status){
if(status){
this.push.unregister().then(function(){
console.log('token deleted');
return true;
})
}
}
startListening(){
if(this.registered){
return this.push.rx.notification()
.subscribe((msg) => {
alert(msg.title + ': ' + msg.text);
});
}}
getToken(){
return this.token.token;
}
}
I have my sender ID for GCM configured in config.xml and ionic cloud, and my APNS certificate is saved in ionic cloud. So far this works perfectly on android. On iOS it registers the token and saves to the database, but testing on Ionic cloud my iPhone doesn't receive any notifications. Any thoughts?