I'm new in OAuth2 and the angular-auth2-oidc library so bear with me if i make some newbie mistakes.
WHAT I WANT TO ACHIEVE: A user will click on the login link in the home page, he will be sent to the provider's site to login and then redirect back to the home page with token.
RESULTS SO FAR: A user is sent to the provider's site to login and sent back to my site's home page successfuly but I don't get any token.
I output some data in the console in the ngOnit()
and they are all null, undefined or false.
Inside the ngOnit()
function also i output some events and the events I get in de console is token_refresh_error
. I don't do any token refresh in my code explicitely but i still get this error.
Under the Error sub-heading of this post I have added screenshots about the errors.
Here are my config and implementation:
Here is the openid configuration of the my OAuth2 provider:
authorization_endpoint "https://DOMAIN_PROVIDER/op/v1/auth"
code_challenge_methods_supported
0 "plain"
1 "S256"
end_session_endpoint "https://DOMAIN_PROVIDER/op/v1/logout"
grant_types_supported
0 "authorization_code"
id_token_signing_alg_values_supported
0 "RS256"
issuer "https://DOMAIN_PROVIDER/op"
jwks_uri "https://DOMAIN_PROVIDER/op/v1/keys"
response_modes_supported
0 "query"
1 "fragment"
2 "form_post"
response_types_supported
0 "code"
scopes_supported
0 "openid"
subject_types_supported
0 "public"
token_endpoint "https://DOMAIN_PROVIDER/op/v1/token"
token_endpoint_auth_methods_supported
0 "client_secret_basic"
1 "client_secret_post"
userinfo_endpoint "https://DOMAIN_PROVIDER/op/v1/userinfo"
Here is my implementation:
// Home page component
export class HomeComponent implements OnInit {
private oAuthConfig: AuthConfig;
constructor(private oAuthService: OAuthService) { }
ngOnInit() {
// IN THIS METHOD I'M OUTPUTTING ALOT OF STUFF TO THE CONSOLE TO SEE IF IT IS WORKING
if (!this.oAuthService.getAccessToken()) {
this.initOAuthConfig();
console.log('__________ACCESS-TOKEN IS NOT SET___________');
} else {
console.log('___ACCESS-TOKEN IS SET:', this.oAuthService.getAccessToken());
}
console.log('_____GRANTED-SCOPE:', this.oAuthService.getGrantedScopes());
console.log('______IDENTITY-CLAIMS:', this.oAuthService.getIdentityClaims());
console.log('______HAS-ACCESS-TOKEN?:', this.oAuthService.hasValidAccessToken());
console.log('_____HAS-ACCESS-TOKEN?:', this.oAuthService.hasValidIdToken());
// HERE I'M OUTPUTTNG THE EVENTS TO SEE WHAT IS GOING ON
this.oAuthService.events.subscribe((e: OAuthErrorEvent) => {
if (e.type === 'token_received') {
this.logger.log('____________TOKEN RECEIVED');
}
this.logger.log('______====================EVENT-TYPE:', e.type);
this.logger.log('______====================EVENT-REASON:', e.reason);
this.logger.log('______====================EVENT-PARAMS:', e.params);
});
if (this.oAuthService.hasValidAccessToken()) {
this.oAuthService.loadUserProfile().then((t) => {
console.log('----USER-PROFILE:', t);
});
} else {
this.logger.log('----HAS VALID ACCESS TOKEN');
}
}
private initOAuthConfig(): void {
this.oAuthConfig = {
redirectUri: window.location.origin + '/login/oauth2/myapp',
postLogoutRedirectUri: window.location.origin + '/logout',
clientId: 'CLIENT-ID',
scope: 'openid, rrn, profile',
oidc: true,
issuer: 'https://DOMAIN_PROVIDER/op',
responseType: 'code',
showDebugInformation: true,
tokenEndpoint: 'DOMAIN_PROVIDER/op/v1/token',
jwks: {'keys': ['DOMAIN_PROVIDER/op/v1/keys']}
};
this.oAuthService.setStorage(sessionStorage);
this.oAuthService.configure(this.oAuthConfig);
this.oAuthService.loadDiscoveryDocumentAndTryLogin();
}
// The class that contains the login function
export class HeaderComponent {
constructor(private oAuthService: OAuthService) { }
public login() {
this.oAuthService.initCodeFlow();
}
public logout() {
this.oAuthService.logOut();
}
}
// The html of the header component which contains the login link
<a (click)="login()" title="Login">
Login
</a>
// Errors / Screenshots of errors
The following are errors in the console when a user is redirected back to the home page
1) In this screenshot the values are null, false or undefined except when discovery document is loaded:
2) In the following screenshot you will see that one of the EVENT-TYPE is token_refresh_error
. and the EVENT-REASON is BAD REQUEST
. It is trying to make a request to https//DOMAIN_PROVIDER/op/v1/token
and is failing though in de initOAuthConfig() method I have added the tokenEndPoint
attribute.
You can also see that the error is error: "invalid_grant"
.
The second line of the screenshot says Error getting token
I added jwks: {'keys': ['https://DOMAIN_PROVIDER/op/v1/keys']}
to initOAuthConfig() thinking that it will solve the problem but it didn't.
// Application tab of the console: Session storage
From the application tab of the console I can see that there are some key-value pairs of data in the session-storage (there is no data in the localstorage) See the next screenshot:
I would aim to implement your solution in 2 stages:
CONFIGURATION FILE
I like to express OAuth settings via JSON configuration - see this file. You can update the file to match your configuration, run my sample, then hopefully you will see a token coming back.
API CLIENT RESPONSIBILITY
When the UI calls the API it must first get an access token, and the UI must also handle expired / 401 responses - see this class.
OAUTH CLIENT RESPONSIBILITY
The API client calls this class to get a token, which uses the OIDC Client library to manage redirects, responses and returning tokens.
EXPLANATORY BLOG POST
See also these write ups, which I've aimed to keep visual and easy to read: