andrea2010
andrea2010

Reputation: 338

Angular/Ruby on Rails/oAuth - The provided authorization grant is invalid

I have a backend written in Ruby on Rails/oAuth it connects with Angular. When creating a user or authentication, I get these errors :

POST https://*=password 401 (Unauthorized)
{"error":"invalid_grant","error_description":"The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client."}

ERROR Error: Uncaught (in promise): {"error":"invalid_grant","error_description":"The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client."}

And

Failed to load https://*/api/users: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://*' is therefore not allowed access. The response had HTTP status code 500.
{
  "isTrusted": true
}

When I log in, the data into the database gets, but still the error flies and you can not log into the account, tell me the problem.

auth.ts :

import { Injectable, Inject }    from '@angular/core';
import { Http, Headers }         from '@angular/http';
import { Router }                from '@angular/router';
import { Location }              from '@angular/common';
import { Subject }               from 'rxjs/Subject';
import { APP_CONFIG, AppConfig } from '../app.config';
import { NotificationsService }  from 'angular2-notifications';

@Injectable()
export class AuthService {
  public accessToken: string;
  public isLoggedIn: Subject<boolean> = new Subject<boolean>();

  private tokenUrl: string;
  private baseUrl: string;
  private headers = new Headers({'Content-Type': 'application/json'});
  private _isLoggedIn: boolean;

  constructor(
    private http: Http,
    private router: Router,
    private location: Location,
    private _flash: NotificationsService,
    @Inject(APP_CONFIG) config: AppConfig
  ) {
    this.baseUrl = config.serverUrl;
    this.tokenUrl = `${config.serverUrl}/oauth/token?client_id=${config.clientId}&grant_type=password`;
  }

  login(user) {
    let body = JSON.stringify(user);
    return this.http.post(this.tokenUrl, body, {headers: this.headers})
      .subscribe(res => {
        if (res.status == 200) {
          this.setAccessToken(res.json().access_token);
          this.setLogIn(true);
          this.router.navigate(['/admin']);
          this._flash.success('', 'Signed in successfully!');
        }
      }, error => {
        this.handleError(error.text(), 'Login failed!')
      });
  }

  logout() {
    this.removeAccessToken();
    this.setLogIn(false);
    this.router.navigate(['/login']);
    this._flash.success('', 'Signed out successfully!');
  }

  registration(user) {
    const url = `${this.baseUrl}/api/users`;
    let body = JSON.stringify({user: user});
    this.http.post(url, body, { headers: this.headers })
      .subscribe(res => {
        if (res.status == 200) {
          this.router.navigate(['/login']);
          this._flash.success(
            'Registration successfully!', 
            'Please check your mailbox and confirm your email address'
          );
        }
      }, error => {
        this.handleError(error.text(), 'Registration failed!')
      });
  }

  checkConfirmationToken(confirmation_token: string): Promise<Object> {
    const url = `${this.baseUrl}/api/users/${confirmation_token}/confirm_email`;
    return this.http.get(url)
      .toPromise()
      .then(res => res.json())
      .catch(error => {
        this.router.navigate(['/login']);
        this.handleError(error, 'Could not confirm email address!');
      });

  }

  private setAccessToken(token: string) {
    localStorage.setItem('token', token);
  }

  private setLogIn(value: boolean) {
    this._isLoggedIn = value;
    this.isLoggedIn.next(this._isLoggedIn);
  }

  private removeAccessToken() {
    localStorage.removeItem('token');
  }

  private handleError(error: any, flash: any = null): Promise<any> {
    console.error(error);
    flash ? this._flash.error('', flash) : null;
    return Promise.reject(error.message || error);
  }
}

Maybe I did not give everything I needed, say what else you need.

Upvotes: 4

Views: 329

Answers (1)

alex kucksdorf
alex kucksdorf

Reputation: 2633

The problem lies not within your frontend, but in your Rails backend. Since the frontend and backend "live" in different origins, you need to allow access from different origins.

The code snippet provided at this blog post should point you in the right direction:

# Gemfile
gem 'rack-cors'

# config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'localhost:4200'
    resource '*',
      headers: :any,
      methods: %i(get post put patch delete options head)
  end
end

For further reading, you can take a look at this detailed post.

Upvotes: 1

Related Questions